Release history
Hivemind turns agent traces into skills and shares with your team releases
All releases
145 shown
CI test matrix + strict install
Tasks removal, permission fix, goal injection
Embedding helper, Pi fix, OpenClaw embedding, Pidfile safety
Standalone embed, Pi fix, OpenClaw embedding, daemon safety
- Updated product positioning to emphasize "auto‑learning, cloud‑backed shared brain"
- Enhanced "How it works" section with a 4‑stage pipeline (trace capture → skill codification → skill propagation → compounding capability) and new diagram
- Added Roadmap section outlining future features: trajectory export for fine‑tuning, dense vector retrieval, skill versioning/review
Full changelog
Summary
Reframes the README from "shared memory / agent amnesia" toward auto-learning: trace capture → skill codification → skill propagation → compounding capability. Tagline kept ("One brain for all your agents").
Source: growth team's positioning draft (SUGGENSTED_README.md, kept locally and not committed). We pulled the language shifts and rejected the technical regressions in their version (renamed env vars, dropped the unified hivemind install flow, simplified per-agent install to manual git clone, single-agent hook lifecycle table).
Changes
- Subtitle:
"Persistent, cloud-backed shared memory"→"Auto-learning, cloud-backed shared brain" - Pull quote: agent-amnesia → Monday→Tuesday migration framing
- Lead paragraph reframed around traces / codified skills / propagated capability
- Feature bullets: Captures · Codifies · Searches · Propagates · Intercepts · Summarizes (was: Captures · Searches · Shares · Intercepts · Summarizes)
- "How it works" section: replaced 3-block diagram with the 4-stage pipeline (trace capture → skill codification → skill propagation → compounding capability), each stage explained in prose, plus a larger 4-block diagram
- Natural search examples mention traces and codified skills
- Team sharing:
"see your memory"→"draw from your team's traces and skills" - Data collection notice: added
Codified skillsrow and workspace-isolation framing - Skills (skilify) intro framed as "where auto-learning becomes concrete"
- New Roadmap section before Security: trajectory export for fine-tuning, dense vector retrieval, skill versioning/review, more agents
Not changed
All technical surface intact: env vars, the unified npm install -g @deeplake/hivemind && hivemind install quick start, per-agent install/uninstall commands, agent-detail collapsibles, embeddings section, summaries env-var table, skilify CLI/triggers/gate-CLI tables, integration-model architecture table, monorepo structure, Security, Development.
Test plan
- [ ] Render preview on GitHub looks right (block quotes, ASCII diagrams)
- [ ] All anchor links still resolve (
#skills-skilifyfrom the new How-it-works section, etc.) - [ ] No remaining stale references — grepping for "memory" over the file shows only legitimate technical identifiers (paths, SQL table name, env var, OpenClaw's separate plugin, skill folder name)
- [ ] Growth team signs off on the language pass
Summary by CodeRabbit
- Documentation
- Updated product positioning and core feature descriptions
- Enhanced "How it works" section with numbered phases and improved architecture diagram
- Refreshed natural search examples and clarified team sharing capabilities
- Expanded data collection notice with additional workspace isolation details
- Added roadmap section with planned feature development items
- Reframed subtitle to "Auto‑learning, cloud‑backed shared brain"
- Added a four‑stage pipeline diagram (trace capture → skill codification → skill propagation → compounding capability)
- Introduced Roadmap section with planned features
Full changelog
Summary
Reframes the README from "shared memory / agent amnesia" toward auto-learning: trace capture → skill codification → skill propagation → compounding capability. Tagline kept ("One brain for all your agents").
Source: growth team's positioning draft (SUGGENSTED_README.md, kept locally and not committed). We pulled the language shifts and rejected the technical regressions in their version (renamed env vars, dropped the unified hivemind install flow, simplified per-agent install to manual git clone, single-agent hook lifecycle table).
Changes
- Subtitle:
"Persistent, cloud-backed shared memory"→"Auto-learning, cloud-backed shared brain" - Pull quote: agent-amnesia → Monday→Tuesday migration framing
- Lead paragraph reframed around traces / codified skills / propagated capability
- Feature bullets: Captures · Codifies · Searches · Propagates · Intercepts · Summarizes (was: Captures · Searches · Shares · Intercepts · Summarizes)
- "How it works" section: replaced 3-block diagram with the 4-stage pipeline (trace capture → skill codification → skill propagation → compounding capability), each stage explained in prose, plus a larger 4-block diagram
- Natural search examples mention traces and codified skills
- Team sharing:
"see your memory"→"draw from your team's traces and skills" - Data collection notice: added
Codified skillsrow and workspace-isolation framing - Skills (skilify) intro framed as "where auto-learning becomes concrete"
- New Roadmap section before Security: trajectory export for fine-tuning, dense vector retrieval, skill versioning/review, more agents
Not changed
All technical surface intact: env vars, the unified npm install -g @deeplake/hivemind && hivemind install quick start, per-agent install/uninstall commands, agent-detail collapsibles, embeddings section, summaries env-var table, skilify CLI/triggers/gate-CLI tables, integration-model architecture table, monorepo structure, Security, Development.
Test plan
- [ ] Render preview on GitHub looks right (block quotes, ASCII diagrams)
- [ ] All anchor links still resolve (
#skills-skilifyfrom the new How-it-works section, etc.) - [ ] No remaining stale references — grepping for "memory" over the file shows only legitimate technical identifiers (paths, SQL table name, env var, OpenClaw's separate plugin, skill folder name)
- [ ] Growth team signs off on the language pass
Summary by CodeRabbit
- Documentation
- Updated product positioning and core feature descriptions
- Enhanced "How it works" section with numbered phases and improved architecture diagram
- Refreshed natural search examples and clarified team sharing capabilities
- Expanded data collection notice with additional workspace isolation details
- Added roadmap section with planned feature development items
- Run `hivemind skilify unpull --legacy-cleanup` on installations ≤ 0.7.13 to clean up old `//SKILL.md` directories.
- The manifest at `~/.deeplake/state/skilify/pulled.json` is now the authoritative source for pulled skills.
- Pulled skill files now stored at `/ -- /SKILL.md` instead of `//SKILL.md`, requiring tools that scan for skills to adjust paths.
- New `hivemind skilify unpull` command with filters (`--user`, `--users`, `--not-mine`, `--dry-run`, `--all`, `--legacy-cleanup`).
- Author‑based organization of pulled skills (e.g., `deploy--alice/`) to coexist with local variants.
Full changelog
Summary
- Pulled skills are now visible to Claude Code. Previously
pullwrote to<root>/<projectKey>/<name>/SKILL.md, but CC's skill loader scans<root>/<dir>/SKILL.md(single depth), so pulled skills appeared inlsbut never reached the agent. New layout writes to<root>/<name>--<author>/SKILL.mdflat — a teammate'sdeployand your locally-mineddeploycoexist asdeploy--alice/anddeploy/. - New
hivemind skilify unpullcommand removes pull-installed skills with--user,--users,--not-mine,--dry-run,--all,--legacy-cleanupfilters. - Manifest at
~/.deeplake/state/skilify/pulled.jsonis the authoritative record of whatpullwrote.unpullonly touches entries in the manifest, so user-authored variant skills with--in the name (e.g.deploy--blue-green) are never removed accidentally. - Visibility wired into all 6 agents (Claude Code, Codex, Cursor, Hermes, Pi, OpenClaw) via SessionStart inject +
hivemind --helpUSAGE block, so the agent suggestsunpullspontaneously. - Fixed a real production bug caught by a unit test:
loadManifest()was returning a shared module-level constant, so everyrecordPullwould have permanently corrupted it across calls.
Layout reference
| Origin | Path on disk |
|---|---|
| Locally mined (your own skill) | <root>/<name>/SKILL.md |
| Pulled (someone else's skill) | <root>/<name>--<author>/SKILL.md |
| Manifest | ~/.deeplake/state/skilify/pulled.json |
<root> is ~/.claude/skills for --to global, <cwd>/.claude/skills for --to project. Atomic write (tmp + rename), 0o600 perms, parent dirs auto-created.
Trade-offs called out in code comments
- Same
(name, author)pulled from two different projects collides on disk under the new flat layout — more recent pull wins, priorSKILL.mdis preserved as.bak. The row stays in the Deeplakeskillstable, recoverable via re-pull from the source project. --alland--legacy-cleanupopt-in flags do an additional disk walk for things NOT in the manifest (locally-mined skills and pre-suffix-author<projectKey>/dirs from skilify ≤ 0.7.13). Always documented as destructive in--help.
Commits in this branch
feat(skilify-pull)— flat<name>--<author>/layout +pulled.jsonmanifestfeat(skilify-unpull)— newunpullcommand with manifest-driven removal + filtersfeat(skilify)— expose unpull to agents via SessionStart inject +--helpbuild(bundles)— regenerate cli.js + per-agent session-start.jsdocs(readme)— document pull / unpull and the new layout
Test plan
- [x] Unit: 69 tests across
skilify-pull.test.ts(43 updated) +skilify-manifest.test.ts(15 new) +skilify-unpull.test.ts(11 new). HOME isolated viamkdtempSyncper test. - [x] Full suite:
npx vitest run— 2103/2104 pass; the single pre-existing failure is indeeplake-api-retry.test.ts(retry timing test, unrelated to skilify). - [x] Build:
npm run build→Built: 12 CC + 10 Codex + 9 Cursor + 9 Hermes + 1 OpenClaw + 1 MCP + 1 CLI + 1 standalone-daemon bundle. - [x] Live e2e against
activeloop/hivemind: verified round-trippull --user d --to global→ disk + manifest both populatedunpull --user d→ both clearedpull --user dagain → re-installs cleanly (idempotent)pull --users d,sasun→ 2 entries, thenunpull --user dremoves only Davit and leaves sasun on both disk and manifest- Manual
deploy--blue-green/directory survived every default unpull invocation - Orphan handling:
pullthenrm -rfthe dir manually thenunpull→ reportsmanifest-orphanand prunes the entry
- [x] CC skill loader confirmation: after
pull --all-users, the SessionStart-loaded skills list shows pulled entries with their proper<name>--<author>identifiers (meta-harness-continual-learning--d,photon-design-feedback--sasun, etc.), proving CC actually picks them up at agent decision time.
Migration
Users on skilify ≤ 0.7.13 with the pre-existing <projectKey>/ layout can clean up legacy directories with:
hivemind skilify unpull --legacy-cleanup --dry-run
hivemind skilify unpull --legacy-cleanup
Otherwise the old directories are left alone (CC ignored them anyway because of the depth-2 issue this PR fixes).
Summary by CodeRabbit
-
New Features
- Added
hivemind skilify unpullcommand to remove previously shared skills with filtering options (--user,--not-mine,--dry-run). - Skills now support author-based organization and removal by install scope.
- Added
-
Documentation
- Updated command reference and help text to document the new unpull functionality and available flags across all tools.
Fixed CI publish step by adding --family code-plugin flag to avoid family change error.
Full changelog
Summary
Adds --family code-plugin to the clawhub package publish invocation in release.yml. Was meant to land in PR #107 but the merge happened before this commit got included — the family-fix commit (5759109) was pushed to that branch but the merge was finalized using an earlier tip. Re-opening it stand-alone here.
Why
After PR #107 merged, the next Release run is going to hit this on the ClawHub publish step:
ConvexError: Package "hivemind" already exists as a code-plugin;
family changes are not allowed
at handler (../convex/packages.ts:4305:8)
The existing hivemind package on ClawHub was originally registered with family=code-plugin (verified via clawhub package inspect hivemind → Family: Code Plugin). The clawhub CLI's auto-detection on this openclaw plugin layout picks a different default (bundle-plugin), so without an explicit --family flag it tries to publish as the wrong family and ClawHub refuses.
Fix
One-line change in .github/workflows/release.yml:
- run: clawhub package publish ./openclaw
+ run: clawhub package publish ./openclaw --family code-plugin
Plus a comment block explaining why.
Verified locally
Test publish run from this machine using the @kaghni token (matches what 1Password now hands CI):
$ clawhub package publish /home/ubuntu/al-projects/hivemind/openclaw \
--family code-plugin --name hivemind --version 0.0.1-test --tags test
- Preparing [email protected]
✔ OK. Published [email protected] (rd7d1frmgts4j1z9mpv9bqk4jd8697hg)
Without --family code-plugin the same auth/data hits family changes are not allowed every time. With it, publish succeeds. Latest tag on ClawHub stayed at 0.6.56 (test publish only set a test tag). Ownership/auth verified working under @kaghni.
Test plan
- [ ] CI passes on this PR
- [ ] On merge: auto-bump fires (0.7.11 → 0.7.12), Release workflow runs, the publish job clears all upstream gates (build, npm publish), and the clawhub publish step now finds the right family and succeeds — ClawHub's
latesttag bumps from 0.6.56 to 0.7.12
Summary by CodeRabbit
- Bug Fixes
- Corrected package publishing configuration to resolve deployment issues during the release process.
Corrected package publishing configuration to resolve deployment issues during the release process.
Full changelog
Summary
Adds --family code-plugin to the clawhub package publish invocation in release.yml. Was meant to land in PR #107 but the merge happened before this commit got included — the family-fix commit (5759109) was pushed to that branch but the merge was finalized using an earlier tip. Re-opening it stand-alone here.
Why
After PR #107 merged, the next Release run is going to hit this on the ClawHub publish step:
ConvexError: Package "hivemind" already exists as a code-plugin;
family changes are not allowed
at handler (../convex/packages.ts:4305:8)
The existing hivemind package on ClawHub was originally registered with family=code-plugin (verified via clawhub package inspect hivemind → Family: Code Plugin). The clawhub CLI's auto-detection on this openclaw plugin layout picks a different default (bundle-plugin), so without an explicit --family flag it tries to publish as the wrong family and ClawHub refuses.
Fix
One-line change in .github/workflows/release.yml:
- run: clawhub package publish ./openclaw
+ run: clawhub package publish ./openclaw --family code-plugin
Plus a comment block explaining why.
Verified locally
Test publish run from this machine using the @kaghni token (matches what 1Password now hands CI):
$ clawhub package publish /home/ubuntu/al-projects/hivemind/openclaw \
--family code-plugin --name hivemind --version 0.0.1-test --tags test
- Preparing [email protected]
✔ OK. Published [email protected] (rd7d1frmgts4j1z9mpv9bqk4jd8697hg)
Without --family code-plugin the same auth/data hits family changes are not allowed every time. With it, publish succeeds. Latest tag on ClawHub stayed at 0.6.56 (test publish only set a test tag). Ownership/auth verified working under @kaghni.
Test plan
- [ ] CI passes on this PR
- [ ] On merge: auto-bump fires (0.7.11 → 0.7.12), Release workflow runs, the publish job clears all upstream gates (build, npm publish), and the clawhub publish step now finds the right family and succeeds — ClawHub's
latesttag bumps from 0.6.56 to 0.7.12
Summary by CodeRabbit
- Bug Fixes
- Corrected package publishing configuration to resolve deployment issues during the release process.
Fixed clawhub package publish failing due to incorrect family flag.
Full changelog
Summary
Adds --family code-plugin to the clawhub package publish invocation in release.yml. Was meant to land in PR #107 but the merge happened before this commit got included — the family-fix commit (5759109) was pushed to that branch but the merge was finalized using an earlier tip. Re-opening it stand-alone here.
Why
After PR #107 merged, the next Release run is going to hit this on the ClawHub publish step:
ConvexError: Package "hivemind" already exists as a code-plugin;
family changes are not allowed
at handler (../convex/packages.ts:4305:8)
The existing hivemind package on ClawHub was originally registered with family=code-plugin (verified via clawhub package inspect hivemind → Family: Code Plugin). The clawhub CLI's auto-detection on this openclaw plugin layout picks a different default (bundle-plugin), so without an explicit --family flag it tries to publish as the wrong family and ClawHub refuses.
Fix
One-line change in .github/workflows/release.yml:
- run: clawhub package publish ./openclaw
+ run: clawhub package publish ./openclaw --family code-plugin
Plus a comment block explaining why.
Verified locally
Test publish run from this machine using the @kaghni token (matches what 1Password now hands CI):
$ clawhub package publish /home/ubuntu/al-projects/hivemind/openclaw \
--family code-plugin --name hivemind --version 0.0.1-test --tags test
- Preparing [email protected]
✔ OK. Published [email protected] (rd7d1frmgts4j1z9mpv9bqk4jd8697hg)
Without --family code-plugin the same auth/data hits family changes are not allowed every time. With it, publish succeeds. Latest tag on ClawHub stayed at 0.6.56 (test publish only set a test tag). Ownership/auth verified working under @kaghni.
Test plan
- [ ] CI passes on this PR
- [ ] On merge: auto-bump fires (0.7.11 → 0.7.12), Release workflow runs, the publish job clears all upstream gates (build, npm publish), and the clawhub publish step now finds the right family and succeeds — ClawHub's
latesttag bumps from 0.6.56 to 0.7.12
Summary by CodeRabbit
- Bug Fixes
- Corrected package publishing configuration to resolve deployment issues during the release process.
- Removed scoped name `@deeplake/hivemind` from `openclaw/package.json:name`; restored bare name `hivemind`.
Full changelog
Summary
Restores openclaw/package.json:name to bare hivemind (its original value), so clawhub package publish ./openclaw succeeds. Sequel to PR #106 — both PRs together unblock the auto-publish flow end-to-end.
What's wrong
After PR #106's fixes landed and the publish job actually got far enough to reach clawhub package publish ./openclaw, ClawHub rejected:
ConvexError: Publisher "@deeplake" not found
at handler (../convex/publishers.ts:389:23)
ClawHub treats the leading @scope in a package name as a publisher namespace and looks it up in its database. There is no @deeplake publisher registered on ClawHub — the existing package on ClawHub is clawhub:hivemind (bare name, owned by the authenticated user's namespace).
openclaw/package.json had name: "@deeplake/hivemind" — the npm scope leaked into the openclaw plugin manifest. Git history shows this was a regression:
- "name": "hivemind", (original)
+ "name": "@activeloop/hivemind",
- "name": "@activeloop/hivemind",
+ "name": "@deeplake/hivemind", (current main)
What changes
One field. openclaw/package.json:name:
- "name": "@deeplake/hivemind",
+ "name": "hivemind",
That's it. The two registries have different namespacing conventions and the manifest already separates plugin identity (name) from code distribution channel (openclaw.install.npmSpec). I'm honoring that separation:
| Field | Value | Used for |
|---|---|---|
| name | hivemind | ClawHub plugin identity (publish + install lookup) |
| openclaw.install.npmSpec | @deeplake/hivemind | npm package the runtime fetches |
Both fields can have different values — that's the whole point of the manifest having two of them.
Effect
clawhub package publish ./openclawpublisheshivemindunder whichever publisher owns theCLAWHUB_TOKEN. That account is already established as the publisher ofclawhub:hivemind(currently at v0.6.56), so this auto-publish picks up the same package and bumps it forward.openclaw plugins install clawhub:hivemind(the existing install command) keeps working — same plugin name on ClawHub.- Once installed, openclaw resolves
npmSpec: @deeplake/hivemind→ fetches the code from npm. Unaffected. - Root
package.json(npm publish) untouched. Still ships as@deeplake/hivemind.
Verified
- Grep across the codebase: nothing reads
openclaw/package.json:nameas a load-bearing string.openclaw.install.npmSpecretains the npm scope, so install logic is untouched. - Live ClawHub state:
https://clawhub.ai/plugins/hivemindshowshivemind(bare) by@kaghni, install viaopenclaw plugins install clawhub:hivemind. The bare name was the original convention.
Test plan
- [ ] CI passes on this PR
- [ ] On merge, the auto-bump triggers
release.yml. The publish job now completes all steps: install → build → quality gate → pack-check → npm publish (provenance succeeds) → clawhub package publish (bare name resolves under token owner) - [ ] Confirm the version on
https://clawhub.ai/plugins/hivemindadvances past 0.6.56
Summary by CodeRabbit
- Package Updates
- Updated package name to improve accessibility and ease of installation.
Fixed release job failures caused by build order and missing repository URL in package.json.
Full changelog
Summary
The publish job in release.yml has been broken since it landed on main — every Release run that actually exercises it has failed. Two independent bugs were gating it; this PR fixes both.
| # | Bug | Failure mode | Fixed by |
|---|---|---|---|
| 1 | Build runs AFTER quality gate | vitest ENOENT on openclaw/dist/index.js | reorder steps in release.yml |
| 2 | package.json has no repository field | npm publish --provenance rejected with HTTP 422 (Sigstore can't verify source URL) | add repository to package.json |
Without both fixes, the publish flow can't ship a release end-to-end. Bug #1 is what's failing right now (run 25484806027 on 5a38c50); bug #2 is what failed run 25482668127 on df5ced18 — the first run that actually got past the quality gate, before PR #98 landed.
Bug #1 — build-before-test
Publish job step order was:
1. npm ci # install deps
2. npm run ci # typecheck + dup + test ← TESTS RUN HERE
3. npm run build # build bundles ← BUILD RUNS AFTER
4. npm run pack:check
5. npm publish --provenance
Bundle-scan tests in claude-code/tests/skilify-session-start-injection.test.ts (added by PR #98) read openclaw/dist/index.js and openclaw/dist/skilify-worker.js directly. openclaw/dist/ is gitignored — only exists after npm run build. Step 2 failed with ENOENT, publish aborted.
Same root cause as 64cac0b (ci: replace typecheck step with full build...) which fixed it for ci.yml's Typecheck and Test job. That fix never propagated to the publish job in release.yml (added later in a436373).
Fix: pure step reorder. Move npm run build before npm run ci.
Bug #2 — provenance verification
npm publish --provenance requires package.json.repository.url to match the source URL claimed by the GitHub Actions OIDC token. package.json on main has no repository field at all, so npm rejects:
npm error 422 Unprocessable Entity - PUT https://registry.npmjs.org/@deeplake%2fhivemind
- Error verifying sigstore provenance bundle: Failed to validate repository information:
package.json: "repository.url" is "", expected to match
"https://github.com/activeloopai/hivemind" from provenance
Bug #1 was masking bug #2 once PR #98 landed (the gate failed before the provenance check could run). Before PR #98 landed, run #95 hit bug #2 directly.
Fix: add the standard npm repository shape:
"repository": {
"type": "git",
"url": "git+https://github.com/activeloopai/hivemind.git"
}
Format follows npm's recommended shape — git+ prefix + .git suffix, both required for provenance to verify.
Test plan
- [ ] CI passes on this PR (the publish job doesn't run on PRs — it's gated
on: push: branches: [main]— so confidence here is by inspection: build is a strict superset of typecheck, and the repository field is mechanically required by npm) - [ ] On merge: auto-bump triggers
release.yml, the bump pushes achore: bump versioncommit which retriggers Release, which runs the publish job. Build runs first → quality gate findsopenclaw/dist/→ vitest passes → build → pack-check →npm publish→ provenance verifies (repository field now present) → ClawHub publish - [ ] Look for
npm notice publish Provenance statement published to transparency log: https://search.sigstore.dev/...followed by HTTP 201 (not 422)
- One‑time setup: create `production` environment, add secrets NPM_TOKEN and CLAWHUB_TOKEN there, ensure workflow has `id-token: write` permission
- Add `npm pack --dry-run` regression guard (`scripts/pack-check.mjs`) to CI runs; it hard‑fails if `files` allowlist includes sensitive paths like .npmrc, .env, .github/, secrets/
- Concurrency guard via `hivemind-publish` job group prevents duplicate publishes of the same version
- Isolates NPM_TOKEN and CLAWHUB_TOKEN to production environment secrets, preventing access from forks or untrusted branches
- Employs ephemeral .npmrc and GitHub auto‑masking of secret values in logs
- Adds npm provenance signing so leaked NPM_TOKEN cannot publish an unsigned package
- Adds `publish` job in release.yml that publishes @deeplake/hivemind to npm and openclaw bundle to ClawHub after version bump
- Enforces GitHub Environment `production` gate with required reviewer for each publish
- Uses npm provenance (`--provenance --access public`) via Sigstore OIDC for verifiable package origin
Full changelog
Summary
- Adds a
publishjob torelease.ymlthat fires after the existing version-bump flow and publishes@deeplake/hivemindto npm and the openclaw bundle to ClawHub - Gated by a
productionGitHub Environment with required reviewer — each version still gets explicit per-publish approval (so this CD does not bypass the existing manual gate, just routes it through GitHub's UI) - npm publish uses
--provenance --access public(Sigstore via GitHub OIDC), so even ifNPM_TOKENlater leaks, consumers can verify the package was built by this workflow on this commit - Adds a
npm pack --dry-runregression guard (scripts/pack-check.mjs, wired into bothci.ymland the publish job) that hard-fails if a PR widens thefilesallowlist to include.npmrc,.env,.github/,secrets/, etc.
Token-leak defenses, layered
- Environment-scoped secrets —
NPM_TOKENandCLAWHUB_TOKENare stored on theproductionenvironment, not the repo. PRs from forks and unprotected branches cannot read them; only the gated publish job can. - Minimum-privilege permissions — workflow stays
contents: readat top, only the publish job addsid-token: write(needed for OIDC provenance). Nopull-requests, no broadercontents: write. - Ephemeral
.npmrc—actions/setup-node@v4writes a temporary~/.npmrcreferencing${NODE_AUTH_TOKEN}; passed only on thenpm publishstep'senv:. The runner's$HOMEis discarded when the job ends. - Sigstore provenance — defense-in-depth even if
NPM_TOKENleaks.npm view @deeplake/hivemind --json | jq .dist.attestationswill show the signature. - GitHub auto-masking — anything flowing through
${{ secrets.* }}is***in logs. We don'tset -xorechoenv on token-bearing steps. - Concurrency guard —
hivemind-publishgroup prevents two merges from racing two publishes of the same version. - Tarball regression guard —
scripts/pack-check.mjsruns in PR CI, so a brokenfilesarray trips on PR review, never on a release run where tokens are reachable.
Required one-time setup before merging
The repo owner must do these in GitHub UI before the first publish run reaches the gate:
- Settings → Environments → New environment named
production- Required reviewers: add your account
- (Optional) Deployment branches: restrict to
main
- Add environment secrets to that environment:
NPM_TOKEN— recommended: granular automation token, scope@deeplake/hivemindonly,Read and write, 90-day expiry. Created at https://www.npmjs.com/settings/~/tokens/granular-access-tokens.CLAWHUB_TOKEN— generate viaclawhub loginand pull the token, or via clawhub.ai web UI.
- Settings → Actions → General → Workflow permissions: confirm
id-token: writeis allowed (some org policies disable it by default).
How it fires after merge
push to main
↓
release job (existing)
├─ first run: bump patch + push back ──► retriggers
└─ bump-commit run: GitHub Release ──► publish job (new)
↓
[GATE: production env approval]
↓
npm publish --provenance
clawhub login --token
clawhub package publish ./openclaw
The publish job's if: requires startsWith(head_commit.message, 'chore: bump version'), so it runs exactly once per released version.
Test plan
- [ ] One-time setup steps above are done before merging this PR
- [ ] On first merge, reject the production environment gate to confirm the gate works without publishing
- [ ] On second merge, approve the gate; verify
npm view @deeplake/hivemind versionmatches the GitHub Release tag - [ ]
npm view @deeplake/hivemind --json | jq .dist.attestationsshows a sigstore attestation (Provenance badge on npmjs.com) - [ ]
clawhub:hivemindis installable andverify-install.shpasses against it - [ ]
gh run view --log <run-id> | grep -E 'npm_[A-Za-z0-9_]{20,}|CLAWHUB_[A-Za-z0-9]{20,}'returns nothing
Confidence
Confidence: 80%, because the npm side is grounded in real package.json + release.yml + standard provenance/Environments practice, and the ClawHub side is grounded in clawhub --help output (clawhub login --token + clawhub package publish <folder> are real subcommands of the published clawhub v0.12.3 package).
Untested:
- Whether
clawhub package publish ./openclawauto-detects the package namehivemindfromopenclaw/openclaw.plugin.json'sidfield, or whether--name hivemindneeds to be passed explicitly - Whether ClawHub has a "trusted publisher" config that would force
--manual-override-reason "Automated CD"to be added — first real publish will surface this if so - Whether
id-token: writeis allowed by the org's current Actions permissions (rules 3 above), since policy may differ per repo - The interaction between the existing release job's git push and the publish job's checkout — current architecture splits across two workflow invocations (the bump-push retriggers), so the publish job sees the bumped commit on
ref: main, but worth visually confirming on the first real run before approving the gate - Whether existing per-bundle E2E (verify-install.sh against installed
@deeplake/hivemind) should be wired into the publish job before npm publish; currently the human reviewer at the gate is the E2E checkpoint
Summary by CodeRabbit
- Chores
- Enhanced CI pipeline with additional validation during pull request testing to safeguard package integrity.
- Implemented automated publishing workflow that handles both npm and ClawHub distribution with environment-based access controls.
- Added validation tooling to verify package contents before publishing.
- One‑time setup: create a `production` environment, add required reviewers, and store `NPM_TOKEN` (scoped to @deeplake/hivemind) and `CLAWHUB_TOKEN` as environment secrets.
- Ensure GitHub Actions workflow permission `id-token: write` is enabled for the repository to allow OIDC token issuance.
- npm publish uses Sigstore provenance (`--provenance`) via GitHub OIDC, allowing verification of package authenticity even if NPM_TOKEN leaks
- Environment‑scoped secrets (`NPM_TOKEN`, `CLAWHUB_TOKEN`) stored only in the `production` GitHub Environment; PRs from forks cannot access them
- Gated production‑environment `publish` job in `release.yml` that runs npm publish with `--provenance --access public` and pushes the openclaw bundle to ClawHub
- `npm pack --dry-run` regression guard (`scripts/pack-check.mjs`) integrated into CI to fail if disallowed files are added to `files` allowlist
Full changelog
Summary
- Adds a
publishjob torelease.ymlthat fires after the existing version-bump flow and publishes@deeplake/hivemindto npm and the openclaw bundle to ClawHub - Gated by a
productionGitHub Environment with required reviewer — each version still gets explicit per-publish approval (so this CD does not bypass the existing manual gate, just routes it through GitHub's UI) - npm publish uses
--provenance --access public(Sigstore via GitHub OIDC), so even ifNPM_TOKENlater leaks, consumers can verify the package was built by this workflow on this commit - Adds a
npm pack --dry-runregression guard (scripts/pack-check.mjs, wired into bothci.ymland the publish job) that hard-fails if a PR widens thefilesallowlist to include.npmrc,.env,.github/,secrets/, etc.
Token-leak defenses, layered
- Environment-scoped secrets —
NPM_TOKENandCLAWHUB_TOKENare stored on theproductionenvironment, not the repo. PRs from forks and unprotected branches cannot read them; only the gated publish job can. - Minimum-privilege permissions — workflow stays
contents: readat top, only the publish job addsid-token: write(needed for OIDC provenance). Nopull-requests, no broadercontents: write. - Ephemeral
.npmrc—actions/setup-node@v4writes a temporary~/.npmrcreferencing${NODE_AUTH_TOKEN}; passed only on thenpm publishstep'senv:. The runner's$HOMEis discarded when the job ends. - Sigstore provenance — defense-in-depth even if
NPM_TOKENleaks.npm view @deeplake/hivemind --json | jq .dist.attestationswill show the signature. - GitHub auto-masking — anything flowing through
${{ secrets.* }}is***in logs. We don'tset -xorechoenv on token-bearing steps. - Concurrency guard —
hivemind-publishgroup prevents two merges from racing two publishes of the same version. - Tarball regression guard —
scripts/pack-check.mjsruns in PR CI, so a brokenfilesarray trips on PR review, never on a release run where tokens are reachable.
Required one-time setup before merging
The repo owner must do these in GitHub UI before the first publish run reaches the gate:
- Settings → Environments → New environment named
production- Required reviewers: add your account
- (Optional) Deployment branches: restrict to
main
- Add environment secrets to that environment:
NPM_TOKEN— recommended: granular automation token, scope@deeplake/hivemindonly,Read and write, 90-day expiry. Created at https://www.npmjs.com/settings/~/tokens/granular-access-tokens.CLAWHUB_TOKEN— generate viaclawhub loginand pull the token, or via clawhub.ai web UI.
- Settings → Actions → General → Workflow permissions: confirm
id-token: writeis allowed (some org policies disable it by default).
How it fires after merge
push to main
↓
release job (existing)
├─ first run: bump patch + push back ──► retriggers
└─ bump-commit run: GitHub Release ──► publish job (new)
↓
[GATE: production env approval]
↓
npm publish --provenance
clawhub login --token
clawhub package publish ./openclaw
The publish job's if: requires startsWith(head_commit.message, 'chore: bump version'), so it runs exactly once per released version.
Test plan
- [ ] One-time setup steps above are done before merging this PR
- [ ] On first merge, reject the production environment gate to confirm the gate works without publishing
- [ ] On second merge, approve the gate; verify
npm view @deeplake/hivemind versionmatches the GitHub Release tag - [ ]
npm view @deeplake/hivemind --json | jq .dist.attestationsshows a sigstore attestation (Provenance badge on npmjs.com) - [ ]
clawhub:hivemindis installable andverify-install.shpasses against it - [ ]
gh run view --log <run-id> | grep -E 'npm_[A-Za-z0-9_]{20,}|CLAWHUB_[A-Za-z0-9]{20,}'returns nothing
Confidence
Confidence: 80%, because the npm side is grounded in real package.json + release.yml + standard provenance/Environments practice, and the ClawHub side is grounded in clawhub --help output (clawhub login --token + clawhub package publish <folder> are real subcommands of the published clawhub v0.12.3 package).
Untested:
- Whether
clawhub package publish ./openclawauto-detects the package namehivemindfromopenclaw/openclaw.plugin.json'sidfield, or whether--name hivemindneeds to be passed explicitly - Whether ClawHub has a "trusted publisher" config that would force
--manual-override-reason "Automated CD"to be added — first real publish will surface this if so - Whether
id-token: writeis allowed by the org's current Actions permissions (rules 3 above), since policy may differ per repo - The interaction between the existing release job's git push and the publish job's checkout — current architecture splits across two workflow invocations (the bump-push retriggers), so the publish job sees the bumped commit on
ref: main, but worth visually confirming on the first real run before approving the gate - Whether existing per-bundle E2E (verify-install.sh against installed
@deeplake/hivemind) should be wired into the publish job before npm publish; currently the human reviewer at the gate is the E2E checkpoint
Summary by CodeRabbit
- Chores
- Enhanced CI pipeline with additional validation during pull request testing to safeguard package integrity.
- Implemented automated publishing workflow that handles both npm and ClawHub distribution with environment-based access controls.
- Added validation tooling to verify package contents before publishing.
- `hivemind workspace ` (bare-target shortcut) no longer switches; it now exits with usage. Use `hivemind workspace switch ` instead.
- Added `workspace list` and `workspace switch <name>` subcommands for explicit workspace management.
- Org switch (`hivemind org switch`) automatically resets the active workspace to `default` with a warning if the previous workspace ID does not exist in the new organization.
Full changelog
Closes #92.
Summary
hivemind workspace <id>no longer silently saves an unknown id. It now lists workspaces, validates id-or-name (case-insensitive), and exits 1 with the available list on miss — same UX ashivemind org switch.hivemind org switchnow resets the active workspace todefault(with a warning) when the previously-saved workspace doesn't exist in the new org. Previously the savedworkspaceIdcarried over silently, leaving the user pointing at a workspace that didn't exist in their new org.- The
workspacecommand surface is restructured intoworkspace listandworkspace switch <name-or-id>, mirroringorg list/org switch. The bare-target shortcut (workspace <id>) is removed.
Why
Two related bugs in the auth-login CLI dispatcher:
switchWorkspaceaccepted any string and persisted it to credentials with no existence check. e.g.hivemind workspace k7printedSwitched to workspace: k7even whenk7was not a real workspace in the current org.switchOrgsaved{ orgId, orgName }without touchingworkspaceId. Afterhivemind org switch <new-org>, you were still scoped to the previous workspace id — which often didn't exist in the new org, so subsequent commands ran against a phantom workspace.
Combined, a user who typed hivemind org switch <other-org> (forgetting to also fix the workspace) ended up silently misconfigured, and even an attempt to fix it with hivemind workspace <id> produced no feedback that the id was wrong.
What changed
src/commands/auth-login.ts
org switchhandler: after the switch, callslistWorkspaces(creds.token, apiUrl, <new-org-id>)and, if the carried-overworkspaceIdisn't in the result, callsswitchWorkspace("default")and prints a warning + the available list.workspacehandler: split into two subcommands.workspace listmirrors the existing top-levelworkspacescommand.workspace switch <target>does the validate-then-switch, exiting 1 with the available list on miss.- Anything else under
workspace(including the previously-supported bare target) is rejected with usage.
- Docstring updated.
src/cli/index.ts
hivemind --helpnow documentsworkspace listandworkspace switch <name-or-id>instead of the bareworkspace <id>form.
claude-code/tests/auth-login-dispatch.test.ts
- Existing
org switchtests updated to mock the newlistWorkspacescall. - Added 10 cases covering:
workspace switch <unknown>exits 1 with the available list, never callsswitchWorkspace.workspace switch <id>andworkspace switch <name>(case-insensitive) both resolve correctly.workspace switch(no target) exits 1 without hitting the API.workspace listis read-only — never callsswitchWorkspace.workspace <target>(the removed bare form) is rejected without API calls — explicit regression guard.org switchresets the workspace todefaultwhen the carried-over id isn't in the new org's list.org switchdoes NOT reset the workspace when the carried-over id (or name) IS still present in the new org.listWorkspacesis called with the NEW org id, not the stale one fromcreds.
Bundles (bundle/cli.js, claude-code/bundle/commands/auth-login.js, codex/bundle/commands/auth-login.js, cursor/bundle/commands/auth-login.js, hermes/bundle/commands/auth-login.js)
- Rebuilt via
npm run build. Second commit is a pure rebuild — no source edits.
Test plan
- [x]
npx vitest run claude-code/tests/auth-login-dispatch.test.ts→ 42/42 pass - [x]
npm run build→ all bundles rebuild cleanly - [x] Local install + smoke tests (overlaid
bundle/cli.jsonto the global@deeplake/hivemindinstall):hivemind workspace list→ lists current org's workspaceshivemind workspace switch <real-name>→ switches successfullyhivemind workspace switch <bogus>→ exits 1 with available list, no state mutationhivemind workspace switch(no arg) → exits 1 with subcommand usage, no API callhivemind workspace <bare-name>→ exits 1 with the new usage linehivemind workspace(no args) → exits 1 with the new usage linehivemind whoamiafter each → confirms credentials state is consistent with the last successful switch
- [ ] Reviewer to verify in a multi-org account:
hivemind org switch <other-org>from a workspace not present in the target org → resets todefaultwith the warning message. (Needs an account with at least two orgs to repro; the unit tests cover the dispatcher logic deterministically.)
Breaking change
hivemind workspace <id> (the bare-target shortcut) no longer switches; it now exits 1 with usage. Replace with hivemind workspace switch <id>. The plural hivemind workspaces command and the /hivemind_switch_workspace OpenClaw slash command are unaffected.
Summary by CodeRabbit
Release Notes
-
New Features
- Added
workspace listandworkspace switch <name-or-id>subcommands for improved workspace management. - Implemented automatic workspace validation during organization switches; resets to default if the workspace is unavailable in the new organization.
- Added
-
Documentation
- Updated CLI usage documentation to reflect new workspace management subcommands.
- `hivemind workspace ` (bare target shortcut) no longer switches; it now exits with usage. Replace with `hivemind workspace switch <name>`.
- Added `workspace list` and `workspace switch <name>` subcommands for explicit workspace management.
- Org switch (`org switch`) automatically resets the active workspace to `default` when the previously‑saved workspace does not exist in the new org, issuing a warning.
Full changelog
Closes #92.
Summary
hivemind workspace <id>no longer silently saves an unknown id. It now lists workspaces, validates id-or-name (case-insensitive), and exits 1 with the available list on miss — same UX ashivemind org switch.hivemind org switchnow resets the active workspace todefault(with a warning) when the previously-saved workspace doesn't exist in the new org. Previously the savedworkspaceIdcarried over silently, leaving the user pointing at a workspace that didn't exist in their new org.- The
workspacecommand surface is restructured intoworkspace listandworkspace switch <name-or-id>, mirroringorg list/org switch. The bare-target shortcut (workspace <id>) is removed.
Why
Two related bugs in the auth-login CLI dispatcher:
switchWorkspaceaccepted any string and persisted it to credentials with no existence check. e.g.hivemind workspace k7printedSwitched to workspace: k7even whenk7was not a real workspace in the current org.switchOrgsaved{ orgId, orgName }without touchingworkspaceId. Afterhivemind org switch <new-org>, you were still scoped to the previous workspace id — which often didn't exist in the new org, so subsequent commands ran against a phantom workspace.
Combined, a user who typed hivemind org switch <other-org> (forgetting to also fix the workspace) ended up silently misconfigured, and even an attempt to fix it with hivemind workspace <id> produced no feedback that the id was wrong.
What changed
src/commands/auth-login.ts
org switchhandler: after the switch, callslistWorkspaces(creds.token, apiUrl, <new-org-id>)and, if the carried-overworkspaceIdisn't in the result, callsswitchWorkspace("default")and prints a warning + the available list.workspacehandler: split into two subcommands.workspace listmirrors the existing top-levelworkspacescommand.workspace switch <target>does the validate-then-switch, exiting 1 with the available list on miss.- Anything else under
workspace(including the previously-supported bare target) is rejected with usage.
- Docstring updated.
src/cli/index.ts
hivemind --helpnow documentsworkspace listandworkspace switch <name-or-id>instead of the bareworkspace <id>form.
claude-code/tests/auth-login-dispatch.test.ts
- Existing
org switchtests updated to mock the newlistWorkspacescall. - Added 10 cases covering:
workspace switch <unknown>exits 1 with the available list, never callsswitchWorkspace.workspace switch <id>andworkspace switch <name>(case-insensitive) both resolve correctly.workspace switch(no target) exits 1 without hitting the API.workspace listis read-only — never callsswitchWorkspace.workspace <target>(the removed bare form) is rejected without API calls — explicit regression guard.org switchresets the workspace todefaultwhen the carried-over id isn't in the new org's list.org switchdoes NOT reset the workspace when the carried-over id (or name) IS still present in the new org.listWorkspacesis called with the NEW org id, not the stale one fromcreds.
Bundles (bundle/cli.js, claude-code/bundle/commands/auth-login.js, codex/bundle/commands/auth-login.js, cursor/bundle/commands/auth-login.js, hermes/bundle/commands/auth-login.js)
- Rebuilt via
npm run build. Second commit is a pure rebuild — no source edits.
Test plan
- [x]
npx vitest run claude-code/tests/auth-login-dispatch.test.ts→ 42/42 pass - [x]
npm run build→ all bundles rebuild cleanly - [x] Local install + smoke tests (overlaid
bundle/cli.jsonto the global@deeplake/hivemindinstall):hivemind workspace list→ lists current org's workspaceshivemind workspace switch <real-name>→ switches successfullyhivemind workspace switch <bogus>→ exits 1 with available list, no state mutationhivemind workspace switch(no arg) → exits 1 with subcommand usage, no API callhivemind workspace <bare-name>→ exits 1 with the new usage linehivemind workspace(no args) → exits 1 with the new usage linehivemind whoamiafter each → confirms credentials state is consistent with the last successful switch
- [ ] Reviewer to verify in a multi-org account:
hivemind org switch <other-org>from a workspace not present in the target org → resets todefaultwith the warning message. (Needs an account with at least two orgs to repro; the unit tests cover the dispatcher logic deterministically.)
Breaking change
hivemind workspace <id> (the bare-target shortcut) no longer switches; it now exits 1 with usage. Replace with hivemind workspace switch <id>. The plural hivemind workspaces command and the /hivemind_switch_workspace OpenClaw slash command are unaffected.
Summary by CodeRabbit
Release Notes
-
New Features
- Added
workspace listandworkspace switch <name-or-id>subcommands for improved workspace management. - Implemented automatic workspace validation during organization switches; resets to default if the workspace is unavailable in the new organization.
- Added
-
Documentation
- Updated CLI usage documentation to reflect new workspace management subcommands.
- Updated Hermes section to describe new shell hooks, shared MCP server, and added recall skill.
- Updated pi section to drop TypeScript extension at ~/.pi/agent/extensions/hivemind.ts enabling auto-capture and registering hivemind tools.
- Completed monorepo structure by adding hermes/, pi/, bundle/, src/embeddings/, src/commands/, src/hooks/hermes, src/hooks/pi directories.
Full changelog
Summary
- Drop the duplicate "Or, if you prefer a global install" block in the Quickstart (both code blocks were identical —
npm install -g @deeplake/hivemind && hivemind install) - Refresh the Hermes Agent section: it no longer says "auto-capture is not yet supported" — the installer now wires shell hooks (
pre_llm_call/post_tool_call/post_llm_call/on_session_end), the shared MCP server, and a recall skill. - Refresh the pi section: drops a TypeScript extension at
~/.pi/agent/extensions/hivemind.ts(subscribing to lifecycle events for auto-capture and registeringhivemind_search/hivemind_read/hivemind_indextools), no per-agent SKILL.md. - Complete the monorepo
hivemind/structure tree: addhermes/,pi/,bundle/,src/embeddings/,src/commands/,src/hooks/hermes,src/hooks/pi. Earlier version omitted half the directories that exist post-9-agent rollout.
Test plan
- [x] Visual diff of README — quickstart no longer shows two identical install blocks
- [x] Hermes section accurately describes installer behavior (cross-checked with
src/cli/install-hermes.ts) - [x] pi section accurately describes installer behavior (cross-checked with
src/cli/install-pi.ts+pi/extension-source/hivemind.ts) - [x] Monorepo tree matches actual
ls hivemind/output
Automatically rebuilds bundles after version bump to include updated version literals.
Full changelog
Why
The auto-release workflow runs `npm version patch` + updates every `plugin.json` on every push to main, but never re-runs `npm run build`. As a result, every release ships bundles whose esbuild-baked literals (notably the `X-Deeplake-Client` header value from `src/utils/client-header.ts`) still carry the PREVIOUS version's string.
CI's `Verify bundle/` check then fails on every subsequent PR until someone manually rebuilds + commits bundles. We have two prior chore commits doing exactly that:
- `6f1d89a chore: rebuild bundles after 0.6.49 → 0.6.50 merge`
- `8f911ba chore: regenerate CC/Codex bundles after rebase merge`
This pattern is the symptom; the root cause is `release.yml`.
What this changes
Inject `npm install && npm run build` into the bump step's run script, between the metadata updates and `git add -A`. Bundles are rebuilt with the new version literal and committed in the same auto-bump commit.
Effect on next release after this lands
- Merge to main triggers `release.yml`
- `npm version patch` (e.g. 0.6.52 → 0.6.53)
- plugin.json / marketplace.json / openclaw.plugin.json all updated
- `npm install` (cheap; lock is satisfied)
- `npm run build` (bundles now contain `hivemind/0.6.53` literals)
- `git add -A` picks up rebuilt bundles
- Single chore commit includes both version bump AND fresh bundles
- Subsequent PRs no longer fail bundle-verify
Unblocks
- PR #81 (README-only change) currently failing CI on the 0.6.50 → 0.6.52 drift
Test plan
- [ ] CI passes on this PR (the workflow itself doesn't run on PRs — it only runs on push to main, so we verify by reading the YAML and confirming syntax)
- [x] YAML still valid (`python3 -c "import yaml; yaml.safe_load(open('.github/workflows/release.yml'))"` → no error)
- [ ] After merge, the next release auto-bump produces fresh bundles and the next PR's bundle-verify passes
Release workflow now rebuilds bundles after version bump to include correct version literals.
Full changelog
Why
The auto-release workflow runs `npm version patch` + updates every `plugin.json` on every push to main, but never re-runs `npm run build`. As a result, every release ships bundles whose esbuild-baked literals (notably the `X-Deeplake-Client` header value from `src/utils/client-header.ts`) still carry the PREVIOUS version's string.
CI's `Verify bundle/` check then fails on every subsequent PR until someone manually rebuilds + commits bundles. We have two prior chore commits doing exactly that:
- `6f1d89a chore: rebuild bundles after 0.6.49 → 0.6.50 merge`
- `8f911ba chore: regenerate CC/Codex bundles after rebase merge`
This pattern is the symptom; the root cause is `release.yml`.
What this changes
Inject `npm install && npm run build` into the bump step's run script, between the metadata updates and `git add -A`. Bundles are rebuilt with the new version literal and committed in the same auto-bump commit.
Effect on next release after this lands
- Merge to main triggers `release.yml`
- `npm version patch` (e.g. 0.6.52 → 0.6.53)
- plugin.json / marketplace.json / openclaw.plugin.json all updated
- `npm install` (cheap; lock is satisfied)
- `npm run build` (bundles now contain `hivemind/0.6.53` literals)
- `git add -A` picks up rebuilt bundles
- Single chore commit includes both version bump AND fresh bundles
- Subsequent PRs no longer fail bundle-verify
Unblocks
- PR #81 (README-only change) currently failing CI on the 0.6.50 → 0.6.52 drift
Test plan
- [ ] CI passes on this PR (the workflow itself doesn't run on PRs — it only runs on push to main, so we verify by reading the YAML and confirming syntax)
- [x] YAML still valid (`python3 -c "import yaml; yaml.safe_load(open('.github/workflows/release.yml'))"` → no error)
- [ ] After merge, the next release auto-bump produces fresh bundles and the next PR's bundle-verify passes
Fixed JSON corruption in captured messages by avoiding double‑escaping backslashes for jsonb columns.
Full changelog
Summary
Codex's capture.ts and stop.ts ran the JSON-encoded message line through sqlStr() before interpolating it into the SQL '...'::jsonb literal. sqlStr() doubles backslashes — correct for standard string columns under legacy Postgres escape syntax, but wrong for jsonb under standard_conforming_strings = on (modern default). The doubling corrupts the JSON-escape sequences, e.g. \" (from JSON.stringify of a string containing a ") becomes literal \\", so jsonb parsing terminates the inner string early and Postgres returns:
400 INVALID_REQUEST: invalid input syntax for type json
Reproduction
Bash tool capture in Codex with any quote-containing input fails outright. Stop captures with quote-containing assistant messages "succeed" but store mangled JSON (literal \n instead of newline, etc.).
Discovered while testing the unified npx installer (#75) end-to-end — every PostToolUse(Bash) event for codex returned 400, with the failing INSERT visible in the hook debug log.
Fix
Apply the same pattern Claude Code's src/hooks/capture.ts:114-116 already uses — only escape ' for the SQL literal, leave JSON-escape sequences untouched:
- const jsonForSql = sqlStr(line);
+ // For JSONB: only escape single quotes for the SQL literal, keep JSON structure intact.
+ // sqlStr() would also escape backslashes and strip control chars, corrupting the JSON.
+ const jsonForSql = line.replace(/'/g, "''");
Two files: src/hooks/codex/capture.ts:101 and src/hooks/codex/stop.ts:104.
Tests
Added regression tests asserting the JSON in the message column round-trips (extracted from the SQL, single-quote-undoubled, then JSON.parse succeeds and matches the original entry):
claude-code/tests/codex-capture-hook.test.ts— quoted Bash command + tool_response, and a user prompt with both"and'claude-code/tests/codex-stop-hook.test.ts— assistant message containing"
If sqlStr() is reintroduced these tests fail at JSON.parse.
Full codex suite: 175 tests pass.
Test plan
- [x]
npm run typecheck— clean - [x]
npx vitest runfor codex tests — 175 pass - [x] Bundle rebuilt (
codex/bundle/capture.js,codex/bundle/stop.jsupdated to match source) - [ ] Live retest: re-run a codex session with HIVEMIND_DEBUG=1 — expect no
[codex-capture] fatallines, expect non-empty session jsonl after a Bash tool call
Fixed JSON corruption in `capture.ts` and `stop.ts` by correctly escaping SQL literals for jsonb columns.
Full changelog
Summary
Codex's capture.ts and stop.ts ran the JSON-encoded message line through sqlStr() before interpolating it into the SQL '...'::jsonb literal. sqlStr() doubles backslashes — correct for standard string columns under legacy Postgres escape syntax, but wrong for jsonb under standard_conforming_strings = on (modern default). The doubling corrupts the JSON-escape sequences, e.g. \" (from JSON.stringify of a string containing a ") becomes literal \\", so jsonb parsing terminates the inner string early and Postgres returns:
400 INVALID_REQUEST: invalid input syntax for type json
Reproduction
Bash tool capture in Codex with any quote-containing input fails outright. Stop captures with quote-containing assistant messages "succeed" but store mangled JSON (literal \n instead of newline, etc.).
Discovered while testing the unified npx installer (#75) end-to-end — every PostToolUse(Bash) event for codex returned 400, with the failing INSERT visible in the hook debug log.
Fix
Apply the same pattern Claude Code's src/hooks/capture.ts:114-116 already uses — only escape ' for the SQL literal, leave JSON-escape sequences untouched:
- const jsonForSql = sqlStr(line);
+ // For JSONB: only escape single quotes for the SQL literal, keep JSON structure intact.
+ // sqlStr() would also escape backslashes and strip control chars, corrupting the JSON.
+ const jsonForSql = line.replace(/'/g, "''");
Two files: src/hooks/codex/capture.ts:101 and src/hooks/codex/stop.ts:104.
Tests
Added regression tests asserting the JSON in the message column round-trips (extracted from the SQL, single-quote-undoubled, then JSON.parse succeeds and matches the original entry):
claude-code/tests/codex-capture-hook.test.ts— quoted Bash command + tool_response, and a user prompt with both"and'claude-code/tests/codex-stop-hook.test.ts— assistant message containing"
If sqlStr() is reintroduced these tests fail at JSON.parse.
Full codex suite: 175 tests pass.
Test plan
- [x]
npm run typecheck— clean - [x]
npx vitest runfor codex tests — 175 pass - [x] Bundle rebuilt (
codex/bundle/capture.js,codex/bundle/stop.jsupdated to match source) - [ ] Live retest: re-run a codex session with HIVEMIND_DEBUG=1 — expect no
[codex-capture] fatallines, expect non-empty session jsonl after a Bash tool call
Fixed JSON corruption in `capture.ts` and `stop.ts` when storing messages as jsonb.
Full changelog
Summary
Codex's capture.ts and stop.ts ran the JSON-encoded message line through sqlStr() before interpolating it into the SQL '...'::jsonb literal. sqlStr() doubles backslashes — correct for standard string columns under legacy Postgres escape syntax, but wrong for jsonb under standard_conforming_strings = on (modern default). The doubling corrupts the JSON-escape sequences, e.g. \" (from JSON.stringify of a string containing a ") becomes literal \\", so jsonb parsing terminates the inner string early and Postgres returns:
400 INVALID_REQUEST: invalid input syntax for type json
Reproduction
Bash tool capture in Codex with any quote-containing input fails outright. Stop captures with quote-containing assistant messages "succeed" but store mangled JSON (literal \n instead of newline, etc.).
Discovered while testing the unified npx installer (#75) end-to-end — every PostToolUse(Bash) event for codex returned 400, with the failing INSERT visible in the hook debug log.
Fix
Apply the same pattern Claude Code's src/hooks/capture.ts:114-116 already uses — only escape ' for the SQL literal, leave JSON-escape sequences untouched:
- const jsonForSql = sqlStr(line);
+ // For JSONB: only escape single quotes for the SQL literal, keep JSON structure intact.
+ // sqlStr() would also escape backslashes and strip control chars, corrupting the JSON.
+ const jsonForSql = line.replace(/'/g, "''");
Two files: src/hooks/codex/capture.ts:101 and src/hooks/codex/stop.ts:104.
Tests
Added regression tests asserting the JSON in the message column round-trips (extracted from the SQL, single-quote-undoubled, then JSON.parse succeeds and matches the original entry):
claude-code/tests/codex-capture-hook.test.ts— quoted Bash command + tool_response, and a user prompt with both"and'claude-code/tests/codex-stop-hook.test.ts— assistant message containing"
If sqlStr() is reintroduced these tests fail at JSON.parse.
Full codex suite: 175 tests pass.
Test plan
- [x]
npm run typecheck— clean - [x]
npx vitest runfor codex tests — 175 pass - [x] Bundle rebuilt (
codex/bundle/capture.js,codex/bundle/stop.jsupdated to match source) - [ ] Live retest: re-run a codex session with HIVEMIND_DEBUG=1 — expect no
[codex-capture] fatallines, expect non-empty session jsonl after a Bash tool call
Fixed JSON corruption in Codex capture and stop hooks by correctly escaping single quotes for SQL literals.
Full changelog
Summary
Codex's capture.ts and stop.ts ran the JSON-encoded message line through sqlStr() before interpolating it into the SQL '...'::jsonb literal. sqlStr() doubles backslashes — correct for standard string columns under legacy Postgres escape syntax, but wrong for jsonb under standard_conforming_strings = on (modern default). The doubling corrupts the JSON-escape sequences, e.g. \" (from JSON.stringify of a string containing a ") becomes literal \\", so jsonb parsing terminates the inner string early and Postgres returns:
400 INVALID_REQUEST: invalid input syntax for type json
Reproduction
Bash tool capture in Codex with any quote-containing input fails outright. Stop captures with quote-containing assistant messages "succeed" but store mangled JSON (literal \n instead of newline, etc.).
Discovered while testing the unified npx installer (#75) end-to-end — every PostToolUse(Bash) event for codex returned 400, with the failing INSERT visible in the hook debug log.
Fix
Apply the same pattern Claude Code's src/hooks/capture.ts:114-116 already uses — only escape ' for the SQL literal, leave JSON-escape sequences untouched:
- const jsonForSql = sqlStr(line);
+ // For JSONB: only escape single quotes for the SQL literal, keep JSON structure intact.
+ // sqlStr() would also escape backslashes and strip control chars, corrupting the JSON.
+ const jsonForSql = line.replace(/'/g, "''");
Two files: src/hooks/codex/capture.ts:101 and src/hooks/codex/stop.ts:104.
Tests
Added regression tests asserting the JSON in the message column round-trips (extracted from the SQL, single-quote-undoubled, then JSON.parse succeeds and matches the original entry):
claude-code/tests/codex-capture-hook.test.ts— quoted Bash command + tool_response, and a user prompt with both"and'claude-code/tests/codex-stop-hook.test.ts— assistant message containing"
If sqlStr() is reintroduced these tests fail at JSON.parse.
Full codex suite: 175 tests pass.
Test plan
- [x]
npm run typecheck— clean - [x]
npx vitest runfor codex tests — 175 pass - [x] Bundle rebuilt (
codex/bundle/capture.js,codex/bundle/stop.jsupdated to match source) - [ ] Live retest: re-run a codex session with HIVEMIND_DEBUG=1 — expect no
[codex-capture] fatallines, expect non-empty session jsonl after a Bash tool call
Fixed JSON corruption when storing quoted strings in Postgres jsonb columns.
Full changelog
Summary
Codex's capture.ts and stop.ts ran the JSON-encoded message line through sqlStr() before interpolating it into the SQL '...'::jsonb literal. sqlStr() doubles backslashes — correct for standard string columns under legacy Postgres escape syntax, but wrong for jsonb under standard_conforming_strings = on (modern default). The doubling corrupts the JSON-escape sequences, e.g. \" (from JSON.stringify of a string containing a ") becomes literal \\", so jsonb parsing terminates the inner string early and Postgres returns:
400 INVALID_REQUEST: invalid input syntax for type json
Reproduction
Bash tool capture in Codex with any quote-containing input fails outright. Stop captures with quote-containing assistant messages "succeed" but store mangled JSON (literal \n instead of newline, etc.).
Discovered while testing the unified npx installer (#75) end-to-end — every PostToolUse(Bash) event for codex returned 400, with the failing INSERT visible in the hook debug log.
Fix
Apply the same pattern Claude Code's src/hooks/capture.ts:114-116 already uses — only escape ' for the SQL literal, leave JSON-escape sequences untouched:
- const jsonForSql = sqlStr(line);
+ // For JSONB: only escape single quotes for the SQL literal, keep JSON structure intact.
+ // sqlStr() would also escape backslashes and strip control chars, corrupting the JSON.
+ const jsonForSql = line.replace(/'/g, "''");
Two files: src/hooks/codex/capture.ts:101 and src/hooks/codex/stop.ts:104.
Tests
Added regression tests asserting the JSON in the message column round-trips (extracted from the SQL, single-quote-undoubled, then JSON.parse succeeds and matches the original entry):
claude-code/tests/codex-capture-hook.test.ts— quoted Bash command + tool_response, and a user prompt with both"and'claude-code/tests/codex-stop-hook.test.ts— assistant message containing"
If sqlStr() is reintroduced these tests fail at JSON.parse.
Full codex suite: 175 tests pass.
Test plan
- [x]
npm run typecheck— clean - [x]
npx vitest runfor codex tests — 175 pass - [x] Bundle rebuilt (
codex/bundle/capture.js,codex/bundle/stop.jsupdated to match source) - [ ] Live retest: re-run a codex session with HIVEMIND_DEBUG=1 — expect no
[codex-capture] fatallines, expect non-empty session jsonl after a Bash tool call
Fixed JSON corruption in `capture.ts` and `stop.ts` by only escaping single quotes for SQL literals.
Full changelog
Summary
Codex's capture.ts and stop.ts ran the JSON-encoded message line through sqlStr() before interpolating it into the SQL '...'::jsonb literal. sqlStr() doubles backslashes — correct for standard string columns under legacy Postgres escape syntax, but wrong for jsonb under standard_conforming_strings = on (modern default). The doubling corrupts the JSON-escape sequences, e.g. \" (from JSON.stringify of a string containing a ") becomes literal \\", so jsonb parsing terminates the inner string early and Postgres returns:
400 INVALID_REQUEST: invalid input syntax for type json
Reproduction
Bash tool capture in Codex with any quote-containing input fails outright. Stop captures with quote-containing assistant messages "succeed" but store mangled JSON (literal \n instead of newline, etc.).
Discovered while testing the unified npx installer (#75) end-to-end — every PostToolUse(Bash) event for codex returned 400, with the failing INSERT visible in the hook debug log.
Fix
Apply the same pattern Claude Code's src/hooks/capture.ts:114-116 already uses — only escape ' for the SQL literal, leave JSON-escape sequences untouched:
- const jsonForSql = sqlStr(line);
+ // For JSONB: only escape single quotes for the SQL literal, keep JSON structure intact.
+ // sqlStr() would also escape backslashes and strip control chars, corrupting the JSON.
+ const jsonForSql = line.replace(/'/g, "''");
Two files: src/hooks/codex/capture.ts:101 and src/hooks/codex/stop.ts:104.
Tests
Added regression tests asserting the JSON in the message column round-trips (extracted from the SQL, single-quote-undoubled, then JSON.parse succeeds and matches the original entry):
claude-code/tests/codex-capture-hook.test.ts— quoted Bash command + tool_response, and a user prompt with both"and'claude-code/tests/codex-stop-hook.test.ts— assistant message containing"
If sqlStr() is reintroduced these tests fail at JSON.parse.
Full codex suite: 175 tests pass.
Test plan
- [x]
npm run typecheck— clean - [x]
npx vitest runfor codex tests — 175 pass - [x] Bundle rebuilt (
codex/bundle/capture.js,codex/bundle/stop.jsupdated to match source) - [ ] Live retest: re-run a codex session with HIVEMIND_DEBUG=1 — expect no
[codex-capture] fatallines, expect non-empty session jsonl after a Bash tool call
- `hivemind_search(query, path?, regex?, ignoreCase?, limit?)` – multi‑word or regex search across both `memory` and `sessions` tables with JSONB normalization.
- `hivemind_read(path)` – fetches full content of a virtual path after a search hit.
- `hivemind_index()` – renders the complete memory index (summaries + sessions) via `readVirtualPathContent`.
Full changelog
Summary
Brings the openclaw hivemind plugin to memory-access parity with the Claude Code and Codex hivemind plugins. Previously, asking "what is Levon doing?" via Telegram -> Haiku returned nothing useful; the same question asked of a CC or Codex agent on the same Hivemind data returns rich info. The accuracy diverged with the plugin, not the data.
Root cause: openclaw's before_agent_start ran a single-keyword ILIKE on the sessions table only, returned five raw JSONB blobs truncated at 300 chars, and gave the agent no way to drill in or re-query. CC and Codex agents use their standard Grep/Read tools against the virtual memory path; a PreToolUse hook rewrites those tool calls into SQL queries that UNION-ALL across both the memory (summaries) and sessions (raw turns) tables with multi-word OR, regex, path filters, and JSONB normalization.
What this PR adds
Three new agent-callable tools registered via pluginApi.registerTool (same pattern used by extensions/memory-wiki):
hivemind_search(query, path?, regex?, ignoreCase?, limit?)— multi-word or regex search across bothmemoryandsessionstables viasearchDeeplakeTables+buildGrepSearchOptions, with JSONB content normalized throughnormalizeContent. Default literal-substring;regex: trueopts into regex.hivemind_read(path)— fetches full content of a virtual path viareadVirtualPathContent. Drill-down after a search hit.hivemind_index()— renders the memory index (all summaries + sessions with dates and descriptions) viareadVirtualPathContent.
All three guarded by if (pluginApi.registerTool) so older openclaw hosts (pre-2026.4.x) silently skip without breaking.
Also registered as a MemoryCorpusSupplement so hosts with a memory_search tool from memory-core federate to hivemind automatically.
before_agent_start auto-recall rewrite
The existing hook now calls searchDeeplakeTables with multi-keyword patterns via buildGrepSearchOptions instead of the first-keyword-only ILIKE — so even hosts without registerTool get better recall. justAuthenticated and no-creds branches preserved.
Implementation approach: reuse, don't refactor
Imports the search/read primitives directly from src/shell/grep-core.ts and src/hooks/virtual-table-query.ts. Those files were already platform-agnostic (take DeeplakeApi + params). No duplication, no changes to CC/Codex call sites. Shared-core extraction stays a future PR when there's time for careful regression testing across all three platforms.
Tests
15 new cases across:
claude-code/tests/openclaw-hivemind-tools.test.ts(11): registration guards, UNION ALL across both tables, multi-word OR filters across both content columns, path scoping, empty-result handling, throw handling, supplement registration, read+index paths.claude-code/tests/openclaw-auto-recall.test.ts(4): short-prompt skip, multi-word UNION ALL, empty-match undefined, throw-handling undefined + logged.
Test plan
- [x]
npm run typecheckclean - [x]
npm run build— 8 CC + 8 Codex + 1 OpenClaw bundles - [x]
npm test— 981/981 across 45 files - [x] Scanner-pattern sweep on openclaw bundle: zero forbidden patterns
- [x] Published to ClawHub as
[email protected]with--display-name "Hivemind" - [ ] E2E on Telegram:
openclaw plugins update hivemind, ask "what is Levon doing?", confirm agent invokeshivemind_searchin the gateway journal and returns hits from both summaries and sessions
Out of scope (future work)
- Extract shared
src/memory-core/used by all three platforms. Do this when there's time for careful regression testing across CC and Codex. - Port per-tool-call capture (CC/Codex capture prompts, tool calls, responses as separate rows; openclaw captures at turn boundary).
- Port wiki-worker background session summarizer to openclaw.
- Added SessionEnd hook `plugin-cache-gc.ts` to garbage‑collect older plugin versions (keeps current + two newest).
- Introduced PID‑scoped snapshot/restore helpers in `src/utils/plugin-cache.ts`.
- Guarded update commands with `|| true` to suppress spurious "autoupdate failed" logs.
Full changelog
Summary
Fixes Stop hook error: Plugin directory does not exist: /…/.claude/plugins/cache/hivemind/hivemind/<old-version> errors that appeared for every post-SessionStart hook (Stop, PostToolUse, SessionEnd) once an auto-update happened mid-session.
- Remove the destructive
rmSyncloop insrc/hooks/session-start.tsthat explicitlyrm -rf'd every non-latest version directory from inside a running session (the actual source of the error — an empiricalclaude plugin updatedoesn't wipe adjacent versions on its own). - Wrap the
claude plugin updateexecSync in bothsession-start.tsandsession-start-setup.tswith a PID-scoped snapshot → restore-or-cleanup dance, so the live session keeps finding its bundle paths even if Claude's installer wipes the versioned directory under some scope. - Add a new
SessionEndhookplugin-cache-gc.tsthat garbage-collects older version directories — keeps the current version plus the two next-newest (DEFAULT_KEEP_COUNT = 3, enough headroom for a session pinned through two further updates) and sweeps up stale.keep-<pid>snapshots from crashed SessionStart updates. - Add a
|| trueguard to each scope insession-start-setup.ts's update command so it stops spuriously loggingautoupdate failedwhen a scope doesn't have hivemind installed.
Why it happens
At session start the hook registry bakes the resolved CLAUDE_PLUGIN_ROOT (e.g. …/hivemind/0.6.38/) into every hook command. When the sync SessionStart hook runs claude plugin update and then iterates the cache directory removing every non-latest version — the currently-executing version among them — later hooks in the same session (Stop, PostToolUse, SessionEnd) all fail with ENOENT on their bundle path. Cleanup now only happens in SessionEnd, by which time the session is gone.
Architecture
src/utils/plugin-cache.ts(new): pure helpers —resolveVersionedPluginDir(dev-layout guard),snapshotPluginDir/restoreOrCleanup(PID-scoped backup/restore around the installer),readCurrentVersionFromManifest,planGc/executeGc(leaves non-semver entries and live-PID snapshots alone, bails if current version isn't on disk).src/hooks/plugin-cache-gc.ts(new): thinrunGc(bundleDir, opts)orchestrator wired as an async SessionEnd hook (15s timeout) alongside the existing summary hook — separate hook to keep the concern isolated and to run even whenHIVEMIND_CAPTURE=falsedisables the summary flow.- Helpers are guarded so a local
--plugin-dirdev run skips all snapshot/GC work and never touches a developer checkout.
Verification
- Full test suite: 46 files / 967 tests pass under
--coverage. - Coverage on the four touched files, ≥ 90 on every metric and locked in
vitest.config.ts:utils/plugin-cache.ts— stmts 93.45, branch 90.47, funcs 100, lines 96.66hooks/plugin-cache-gc.ts— 100 / 100 / 100 / 100hooks/session-start.ts— 98.82 / 90.47 / 100 / 98.76hooks/session-start-setup.ts— 100 / 100 / 100 / 100
- Real
claude -p --plugin-dir ./claude-codewithclaude-code/.claude-plugin/plugin.jsonmanually lowered to0.6.30(to force the update path) — hook-debug.log shows both autoupdate paths firing withautoupdate snapshot outcome: noop(dev-layout guard correct) andautoupdate succeeded, no morecache cleanup: removed old versionlines, andplugin-cache-gcskipping correctly. - Subprocess integration test
plugin-cache-gc-bundle.integration.test.tsruns the actual shippedplugin-cache-gc.jsbundle against a fakeHOME— validates keep-current-plus-two, preserves live-PID snapshots, bails without a manifest, and skips dev layouts. - Empirical check: a ghost
0.6.40-ghost/directory survived a no-opclaude plugin update— confirms the installer doesn't wipe adjacent versions on its own, so the destructivermSyncloop was responsible for the errors observed in production. (A real version-bump install could still wipe the directory on its own; the snapshot/restore dance handles that case too.)
Known limitation
Accepted tradeoff: a session pinned to version X through three further updates can still lose its bundle. Reference-counting per version would close this; deferred as out of scope. N = 3 gives two updates of headroom, which covers every real-world scenario observed so far.
Test plan
- [ ] CI green (tests + coverage thresholds + PR coverage comment ≥ 90 on the four files).
- [ ] Smoke test in a real install: run any Claude session, trigger an auto-update by bumping the published version beyond the installed one, confirm no
Plugin directory does not existerrors in subsequent hooks. - [ ] Next SessionEnd cleans old versions down to 3 (observe in
hook-debug.log: [plugin-cache-gc] gc kept=… deletedVersions=…).
- Added `/hivemind_update` command with dynamic node:fs import for scanner safety
- Updated OpenClaw documentation to include coexist callout, troubleshooting steps, and disabled `openclaw model` CLI
Full changelog
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— removekind: "memory"from export, removeaddToLoadPaths(), add/hivemind_updatecommand with dynamic node:fs import (scanner-safe), alignedinstall→updateverb in logsopenclaw/skills/SKILL.md— disclose credential storage, auto-capture, network destination; single## Commandssection with/hivemind_updateopenclaw/README.md— (new file) coexist callout + troubleshooting for model-ID allowlist, disabledopenclaw modelCLI, telegram-elevated gotchas, EACCES on self-updateREADME.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 #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, butaddToLoadPathsand the rest of the regressions are present)
Test plan
- [x]
npm run typecheckclean - [x]
npm run build— 8 CC + 8 Codex + 1 OpenClaw bundles - [x]
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
Reverts accidental PR #66 merge, preserving version bump commits and retaining version 0.6.41.
Full changelog
Summary
Reverts PR #66 (feat/openclaw-coexist, merge commit d3fc604). It was merged by mistake — the intended merge was PR #67 (feat/locomo-accuracy-v3).
What this revert does
- Undoes the changes from the merge commit's second parent (the OpenClaw-coexist branch).
- Preserves the version bump commits that landed after the merge (
5870714→ 0.6.40,b308d6e→ 0.6.41). Reverting them too would create an ordering headache with the auto-bump pipeline; they're no-op chores that the next release can renumber if needed. - Version files (
package.json,plugin.json,marketplace.json) kept at 0.6.41 (HEAD). Everything else rolled back to pre-#66 state.
Next step
Once this merges, PR #66 can be re-reviewed and merged cleanly on its own, and PR #67 (the locomo accuracy work originally intended) can be merged.
Test plan
- [ ] Branches clean up: 4 files reverted (README.md, openclaw/README.md, openclaw/skills/SKILL.md, openclaw/src/index.ts)
- [ ] No unrelated changes
- [ ] CI green
Reverts mistakenly merged PR #66 to restore the pre‑merge state while keeping version bump commits.
Full changelog
Summary
Reverts PR #66 (feat/openclaw-coexist, merge commit d3fc604). It was merged by mistake — the intended merge was PR #67 (feat/locomo-accuracy-v3).
What this revert does
- Undoes the changes from the merge commit's second parent (the OpenClaw-coexist branch).
- Preserves the version bump commits that landed after the merge (
5870714→ 0.6.40,b308d6e→ 0.6.41). Reverting them too would create an ordering headache with the auto-bump pipeline; they're no-op chores that the next release can renumber if needed. - Version files (
package.json,plugin.json,marketplace.json) kept at 0.6.41 (HEAD). Everything else rolled back to pre-#66 state.
Next step
Once this merges, PR #66 can be re-reviewed and merged cleanly on its own, and PR #67 (the locomo accuracy work originally intended) can be merged.
Test plan
- [ ] Branches clean up: 4 files reverted (README.md, openclaw/README.md, openclaw/skills/SKILL.md, openclaw/src/index.ts)
- [ ] No unrelated changes
- [ ] CI green
Reverts the mistakenly merged OpenClaw-coexist feature while preserving version bump commits.
Full changelog
Summary
Reverts PR #66 (feat/openclaw-coexist, merge commit d3fc604). It was merged by mistake — the intended merge was PR #67 (feat/locomo-accuracy-v3).
What this revert does
- Undoes the changes from the merge commit's second parent (the OpenClaw-coexist branch).
- Preserves the version bump commits that landed after the merge (
5870714→ 0.6.40,b308d6e→ 0.6.41). Reverting them too would create an ordering headache with the auto-bump pipeline; they're no-op chores that the next release can renumber if needed. - Version files (
package.json,plugin.json,marketplace.json) kept at 0.6.41 (HEAD). Everything else rolled back to pre-#66 state.
Next step
Once this merges, PR #66 can be re-reviewed and merged cleanly on its own, and PR #67 (the locomo accuracy work originally intended) can be merged.
Test plan
- [ ] Branches clean up: 4 files reverted (README.md, openclaw/README.md, openclaw/skills/SKILL.md, openclaw/src/index.ts)
- [ ] No unrelated changes
- [ ] CI green
- Update the plugin via `openclaw plugins install clawhub:hivemind`; ensure memory‑core dreaming cron (`0 3 * * *`) continues running after upgrade.
- Review new troubleshooting docs for model tuning, allowlist restrictions, CLI disable defaults, and npm EACCES handling.
- Passive version check at registration with `/hivemind_update` command for explicit updates
- Plugin now coexists with `extensions/memory-core`: removed `kind: "memory"` and `addToLoadPaths()` to avoid slot conflict
Full changelog
Summary
Consolidates and lands the two open OpenClaw plugin PRs (#49 autoupdate, #58 coexist-with-memory-core), resolves their merge conflicts cleanly, and adds real-world troubleshooting docs from a 2026-04-17 debug session.
Closes #49 and closes #58 — both OPEN and conflicting with recent main; rather than rebasing two branches in parallel, they're merged here with conflicts resolved and bugs fixed.
What's in this branch
From PR #58 (coexist with memory-core)
- Remove
kind: "memory"fromopenclaw/openclaw.plugin.json— hivemind no longer claims OpenClaw's memory slot - Remove
addToLoadPaths()— plugin no longer mutates~/.openclaw/openclaw.json - Create
openclaw/README.md(didn't exist on main) - Update global
README.mdandSKILL.md
Why it matters: extensions/memory-core owns the dreaming cron ("0 3 * * *") and the light/REM/deep memory-consolidation phases. When hivemind declared kind: "memory", it grabbed 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): a memory-adjacent plugin that augments the active memory backend rather than replacing it.
From PR #49 (autoupdate / version-check)
- Passive version check at plugin registration; logs update notice if behind
/hivemind_updatecommand for explicit check
Fixes discovered during merge
- PR #49 referenced an undefined
GITHUB_RAW_PKG— the declared constant isVERSION_URL. Fixed. - PR #58 removed
readFileSync/joinimports (security scanner), but PR #49'sgetInstalledVersion()uses them. Resolved by movingnode:fs/node:pathto dynamic imports inside the function — source stays scanner-clean, functionality preserved. - Duplicate org-command commits from PR #58 that already landed via PR #52 merged cleanly (ort strategy recognized them).
New documentation
Troubleshooting section in both global and openclaw READMEs covering issues found during the 2026-04-17 debug:
- Agent model tuning (Opus-4 default is too slow for memory workflows; recommend
anthropic/claude-haiku-4-5-20251001) - OpenClaw's strict provider-prefixed + dated model-ID allowlist (rejects
-latestand unprefixed IDs) openclaw model <id>CLI being disabled by default (plugins.allowexcludesmodel)tools.elevated.allowFrom.<provider>gate for channel-triggered elevated commandsnpm EACCESon self-update when OpenClaw is installed under a root-owned npm prefix
Test plan
- [x]
npm run typecheck— clean - [x]
npm run build— 8 CC + 8 Codex + 1 OpenClaw bundles built - [x]
npm test— 918/918 passing across 41 files - [ ] Install via
openclaw plugins install clawhub:hivemindand verifymemory-coredreaming cron still runs - [ ] Verify
/hivemind_updatereports correct state against current main
Follow-ups (not in this PR)
- Migrate
getInstalledVersion/isNewerto the sharedsrc/utils/version-check.tshelper (needs a small extension for openclaw's non-standard manifest filename) - Port recent CC/codex fixes to OpenClaw: 8KB output cap, SQL
ESCAPE '\\', release-lock observability,src/utils/helper migration
🤖 Generated with Claude Code
Five bug fixes close a 48‑point accuracy gap between cloud and local LoCoMo baselines.
Full changelog
Summary
Five bug fixes to the pre-tool-use hook and shell bundle that close the 48-point accuracy gap between the local-files LoCoMo baseline and the cloud baseline on a sessions-only Deeplake workspace.
Stacked on top of optimizations (PR #61). Keeps Davit's grep refactor, adds five independent fixes plus 44 unit/integration tests that fail if any fix regresses.
Headline numbers
100-QA LoCoMo run, deterministic first-100 QAs from locomo10.json, Haiku model, Gemini judge via openrouter/google/gemini-2.5-flash. Sessions-only workspace locomo_benchmark/baseline (272 raw sessions in sessions, memory table dropped).
| Run | Fixes | Accuracy | Gap to local (75.0%) |
|---|---|---:|---:|
| baseline_cloud (original, reference) | none | 27.0% | −48.0 pt |
| baseline_cloud_100qa_fix123 | #1 + #2 + #3 | 67.5% | −7.5 pt |
| baseline_cloud_100qa_fix12345 | #1 + #2 + #3 + #4 + #5 | 68.0% | −7.0 pt |
| baseline-100-subset (local, no plugin) | n/a | 75.0% | — |
Per-category accuracy (full 100-QA runs)
| Cat | Label | n | Pre-fix | +fix 1–3 | +fix 1–5 |
|---|---|---:|---:|---:|---:|
| 1 | single-hop | 32 | 15.6% | 42.2% | 50.0% |
| 2 | temporal | 37 | 36.5% | 81.1% | 85.1% |
| 3 | multi-hop | 13 | 23.1% | 69.2% | 61.5% |
| 4 | open-domain | 18 | 30.6% | 83.3% | 69.4% |
Signal quality at the tool boundary
| Signal | Pre-fix | +fix 1–3 | +fix 1–5 |
|---|---:|---:|---:|
| [deeplake-sql] lines in tool_result | 35+ | 0 | 0 |
| "path must be of type string" errors | 60+ | 0 | 0 |
| Read-tool calls that succeeded | 0 | 201 | ~250 |
| (no matches) on conv_N_session_*.json globs | many | 19 QA × 3+ | much lower |
The five fixes
#1 — /index.md lists session files too (4271baf)
Bug: the virtual /index.md was generated from the memory table only (WHERE path LIKE '/summaries/%'). In workspaces where that table was empty or dropped (e.g. locomo_benchmark/baseline), the index reported 0 sessions: or 1 sessions: even when the sessions table had 272 rows. Claude concluded memory was empty and gave up.
Fix: buildVirtualIndexContent(summaryRows, sessionRows) now renders both under ## Summaries / ## Sessions sections with a combined header (273 entries (1 summaries, 272 sessions):). The fallback path in readVirtualPathContents queries both tables in parallel and passes both sets to the builder.
Files: src/hooks/virtual-table-query.ts.
Tests: claude-code/tests/virtual-table-query.test.ts adds four cases covering the regression, the backwards-compatible single-arg call, and the empty case. claude-code/tests/pre-tool-use-baseline-cloud.test.ts drives the full processPreToolUse flow against a 272-row fixture and asserts the synthesized index contains every real session path.
#2 — Read-tool intercepts return file_path, not command (4c5d50b)
Bug: the hook's updatedInput was always Bash-shaped ({command, description}). When the incoming tool was Read, Claude Code's Read implementation looked for updatedInput.file_path, found undefined, and crashed with "The 'path' property must be of type string, got undefined". On the pre-fix sessions-only 100-QA run, every memory-path Read call hit this error (9 / 9 tracked cases); on the plugin-v8-optimizations-100 run, 60 / 100 transcripts contained the error.
Fix: extended ClaudePreToolDecision with an optional file_path field. For Read-tool intercepts, the plugin materializes the fetched content via writeReadCacheFile(sessionId, virtualPath, content) into ~/.deeplake/query-cache/<sessionId>/read/<virtualPath> and returns a decision with file_path set. main() dispatches on file_path: if present, emits updatedInput: {file_path}; otherwise keeps the historical {command, description}. Bash / Grep / Glob paths are unchanged.
Files: src/hooks/pre-tool-use.ts.
Tests: pre-tool-use-baseline-cloud.test.ts now asserts Read intercepts produce a decision with file_path, with content captured through a stubbed writeReadCacheFileFn. hooks-source.test.ts cases updated to match.
#3 — Shell bundle silences [deeplake-sql] trace in one-shot mode (35a7e87)
Bug: Claude Code's Bash tool merges a child process's stderr into the tool_result string the model sees. The shell bundle, when invoked as node shell-bundle -c "…" from the pre-tool-use hook, wrote [deeplake-sql] query start: … lines to stderr whenever HIVEMIND_TRACE_SQL / HIVEMIND_DEBUG was set — which in CI / dev shells was frequently the case. The model saw SQL log noise instead of grep output; on the original baseline_cloud-100 run, 35+ trace lines leaked across the transcripts.
Fix: two parts.
- Move the
TRACE_SQL/DEBUG_FILE_LOGchecks insrc/deeplake-api.tsout of module-level constants and into thetraceSqlfunction body so callers can flip the env vars at runtime. - In
src/shell/deeplake-shell.ts, when the bundle detects one-shot mode (-cin argv),delete process.env[…]forHIVEMIND_TRACE_SQL,DEEPLAKE_TRACE_SQL,HIVEMIND_DEBUG,DEEPLAKE_DEBUGbefore opening any SQL connection. Interactive REPL mode keeps the env untouched.
Files: src/deeplake-api.ts, src/shell/deeplake-shell.ts.
Tests: claude-code/tests/shell-bundle-sql-trace-silence.test.ts spawns the shipped bundle with the trace vars set, points it at an unreachable API, and asserts stderr is free of [deeplake-sql]. Source-level check confirms traceSql reads env at call time, not at module load.
#4 — LIKE clauses that consume sqlLike() output use ESCAPE '\' (3d15454)
Bug: sqlLike(value) escapes _ and % by prefixing them with \ so callers can safely interpolate user-controlled strings into LIKE 'pattern' literals. But the Deeplake backend does not treat backslash as the LIKE escape character by default — without an explicit ESCAPE '\' clause, \_ is matched as two literal characters instead of a literal _. Every query whose path or filename contained _ (e.g. /sessions/conv_0_session_N.json) silently returned zero rows.
Observed in the wild: grep "adoption agency" ~/.deeplake/memory/sessions/conv_0_session_*.json returned (no matches) even though "adoption agency" is in the file — the LIKE pattern /sessions/conv\_0\_session\_%.json never matched any real path.
Fix: append ESCAPE '\' to every LIKE '...' clause that is fed from sqlLike(). Covers:
src/shell/grep-core.ts:buildPathCondition(wildcard-path and directory-prefix branches).src/hooks/virtual-table-query.ts:buildDirFilter(per-directory filters used bylistVirtualPathRowsForDirs).src/hooks/virtual-table-query.ts:findVirtualPaths(memory- and sessions-table branches, path and filename clauses).
The Codex and Claude Code find fallbacks and bash-command-compiler's find_grep segment call through to findVirtualPaths and inherit the fix without a local change.
Files: src/shell/grep-core.ts, src/hooks/virtual-table-query.ts.
Validation: focused 15-QA subset run (baseline_cloud_15qa_fix4) on the 15 regressions where local=1 and cloud<1 after fix #1+#2+#3. Pre-fix-4: 1.5 / 15 pts. Post-fix-4: 13.0 / 15 pts, ties the local score exactly. 14 / 15 QAs improved, 1 stayed partial, 0 regressed.
#5 — Cap plugin tool output at 8 KB (2c0d65d)
Bug: Claude Code's Bash tool silently persists any tool_result larger than ~16 KB to disk and replaces it with a 2 KB preview plus a path to the persisted file. In the baseline_cloud_100qa_fix123 run, 11 of 14 losing QAs that hit this path never read the persisted file — the 2 KB preview was too small to carry the answer and the model gave up.
Typical triggers: grep -r Caroline /home/.deeplake/memory/ (Caroline appears in nearly every session → 66 KB of dialogue), for f in /…/sessions/conv_0_session_*.json; do grep …; done (926 KB of concatenated output through the slow-path shell bundle).
Fix: src/utils/output-cap.ts exports capOutputForClaude(output, {kind}). If the output fits under 8 KB (CLAUDE_OUTPUT_CAP_BYTES) it is returned unchanged; otherwise it is truncated at the last line boundary that fits under the cap, and a short footer is appended:
... [grep truncated: 313 more lines (58.4 KB) elided — refine with '| head -N' or a tighter pattern]
The footer names the operation (grep / cat / ls / find / bash) and gives the model a concrete next step. The cap is applied on every plugin exit path that can produce a Bash-tool result:
grep-direct.ts:handleGrepDirect(grep output)bash-command-compiler.ts:executeCompiledBashCommand(final concatenation of compiled segments)pre-tool-use.tsdirect read (cat/head/tail),ls, andfindfallbacks
Read-tool intercepts are unaffected: they write content to disk and return a file_path, so no Claude Code preview truncation applies.
Files: src/utils/output-cap.ts, src/hooks/grep-direct.ts, src/hooks/bash-command-compiler.ts, src/hooks/pre-tool-use.ts.
Tests: claude-code/tests/output-cap.test.ts (8 cases) covers the no-op path, line-boundary truncation, single-oversized-line path, custom maxBytes, the default footer kind, and a realistic 400-line grep fixture that exceeds 16 KB and gets capped strictly between 4 KB and 8 KB.
Test coverage
44 unit and integration tests across four files, all passing:
claude-code/tests/virtual-table-query.test.ts— 21 tests. Covers fix #1 at the builder level and thereadVirtualPathContentsfallback (both branches of the "memory empty" / "sessions empty" matrix). Asserts the exact SQL shape per branch.claude-code/tests/pre-tool-use-baseline-cloud.test.ts— 13 tests. Real-QA-anchored integration tests drivingprocessPreToolUseagainst a workspace mock with 272 session rows. Every case mirrors a concrete LoCoMo QA from the benchmark (conv 0 / qa 3, 6, 25, 29, 46). Asserts fix #1 and fix #2 at the entry point; one dedicated test for Read against a/sessions/<file>.jsonpath (not just/index.md).claude-code/tests/shell-bundle-sql-trace-silence.test.ts— 2 tests. Bundle-level regression guard for fix #3.claude-code/tests/output-cap.test.ts— 8 tests. Byte-accurate truncation assertions for fix #5.
Each fix was independently verified by stashing the source change and re-running the relevant test file — every source-stash produces a failing test that pinpoints the regression. Verification notes live in the individual commit messages.
Non-determinism caveat (honest)
Haiku and the Gemini judge introduce run-to-run variance that is much larger than the signal we're measuring at 100-QA scale. On the full 100-QA set, the fix 1+2+3+4+5 run scored 68.0 % vs fix 1+2+3's 67.5 % — a 0.5-point net delta. This is not proof that fixes #4 and #5 are net-zero at that scale.
The decisive evidence is in the focused subsets:
- Fix #4's 15-QA regression subset: 1.5 → 13.0 / 15 pts, a +76.7 pp swing. Every improved QA used an underscored glob that was previously silently returning zero rows.
- Fix #5 verified empirically:
grep -r Caroline /home/.deeplake/memory/went from ~66 KB of output truncated to a 2 KB preview (Claude rarely recovered) to a capped 7.9 KB chunk with a footer reporting 313 elided lines.
A 14-QA re-run on an identical fix state produced 14.3 % in one run and 53.6 % in another — a 39-point swing from pure Haiku + judge non-determinism. In other words, a single 100-QA run carries ±3–4 points of noise, and the +0.5 pt cross-run delta is well inside that band. The true effect of fixes #4 and #5 on the full 100 is masked by the noise; the per-fix subset tests are the honest measurement.
Plugin workspace cross-check
Same build, same 100-QA set, but against locomo_benchmark/plugin (272 summaries + 272 sessions) instead of the sessions-only baseline workspace:
| Workspace | Fixes | Accuracy |
|---|---|---:|
| locomo_benchmark/baseline (sessions only) | #1–#5 | 68.0 % |
| locomo_benchmark/plugin (sum + ses) | #1–#5 | 70.5 % |
Davit's pre-fix plugin-v8-optimizations-100 scored 71.0 % on the canonical 45+55 subset against the same plugin workspace. The fix 1–5 build on the different first-100 subset is statistically indistinguishable.
The +2.5 pt from adding summaries is smaller than Davit's observed +11 pt (v8 baseline-workspace → v8 optimizations) because fixes #1–#3 already close most of the sessions-only gap: with the raw-session path working, the summaries are no longer compensating for retrieval-path bugs.
Full analysis lives in deeplake-cli-locomo-benchmark_plugin/results/ablation_cloud_plugin_fixes.md (benchmark repo).
Reproduction
# Point the Hivemind CLI at the sessions-only baseline workspace.
hivemind org switch locomo_benchmark
hivemind workspace baseline
# Benchmark.
cd deeplake-cli-locomo-benchmark_plugin
rm -rf ~/.deeplake/query-cache/
env -u HIVEMIND_TRACE_SQL -u DEEPLAKE_TRACE_SQL -u HIVEMIND_DEBUG -u DEEPLAKE_DEBUG \
PLUGIN_DIR=/…/worktrees/davit_pr/claude-code \
DEEPLAKE_CAPTURE=false HIVEMIND_CAPTURE=false \
bun scripts/run-benchmark.ts \
--table sessions --limit 100 --run-id <run-id> \
--concurrency 10 --timeout 180 --log-tools
Test plan
- [x]
npm run buildsucceeds (8 Claude Code + 8 Codex + 1 OpenClaw bundles). - [x]
npx vitest run claude-code/tests/virtual-table-query.test.ts claude-code/tests/pre-tool-use-baseline-cloud.test.ts claude-code/tests/shell-bundle-sql-trace-silence.test.ts claude-code/tests/output-cap.test.ts— 44 / 44 pass. - [x] End-to-end benchmark on
locomo_benchmark/baselinereaches 68.0 % (vs 27.0 % pre-fix, vs 75.0 % local). - [x] Plugin-workspace cross-check reaches 70.5 %.
- [x] Every fix has a regression test that fails if the source change is stashed.
- [ ] Reviewer smoke-check: reproduce the
fix415-QA regression subset run on a fresh checkout. - [ ] Optional follow-ups tracked separately (not in this PR): BM25 via
content_text <#>for pattern-variation robustness;ORDER BYinsidegrep-core.ts:searchDeeplakeTablessubqueries to remove the remaining plugin-side non-determinism fromLIMIT 100.
- DEEPLAKE_* environment variable aliases are removed; use HIVEMIND_CAPTURE instead to disable capture.
- Removed DEEPLAKE_CAPTURE and DEEPLAKE_WIKI_WORKER env var fallbacks
Full changelog
Summary
Three related cleanups on top of the periodic-summary feature that landed in #59.
- Race fix:
SessionEnd(Claude Code) andStop(Codex) now acquire the per-session advisory lock before spawning the wiki worker. If the capture hook already spawned a periodic worker, the SessionEnd/Stop handler bails out with a log line instead of starting a second one. Two concurrent workers writing the same summary row trip the documented Deeplake quirk (rapid UPDATEs on the same row silently drop one), so this was a real correctness bug waiting to happen. DEEPLAKE_*env var cleanup: removes theDEEPLAKE_WIKI_WORKER/DEEPLAKE_CAPTUREfallbacks across 8 hook files. Both are internal flags set by the plugin on itself — the aliases existed for back-compat with pre-rename installs (0.6.35 PR #52). A latent bug insession-start.ts:179was reading only the old name, so users settingHIVEMIND_CAPTURE=falsestill had the placeholder INSERT fire. Fixed.- Tests: raises the coverage on every touched hook from 0% to ~95–100%, plus new coverage for
summary-state.ts(the lock / trigger logic that had no direct tests) and a bundle-level anti-regression suite.
Why this matters
The periodic-summary feature triggers the wiki worker from inside the capture hook once the message threshold crosses. Before this PR the capture hook guarded the spawn with tryAcquireLock, but SessionEnd / Codex Stop did not. On real sessions where periodic just fired, SessionEnd would fire a few seconds later and spawn a second worker. Both workers then race on the same summary row. The Deeplake backend silently drops one of two rapid UPDATEs on the same row (see CLAUDE.md — this is the same quirk that forced uploadSummary into a single-statement write), so the session summary could end up missing either the summary column or the description column, with no error returned.
The DEEPLAKE_* aliases were pure noise on internal flags. They also masked the latent bug in session-start.ts where the placeholder INSERT ignored HIVEMIND_CAPTURE=false — capture was disabled everywhere except the one path driven by session-start.ts.
What's in the PR
Code (fixes)
| Commit | Change |
|---|---|
| fix(session-end) | tryAcquireLock before spawn in src/hooks/session-end.ts |
| fix(codex-stop) | tryAcquireLock before spawn in src/hooks/codex/stop.ts |
| fix(session-start) | read HIVEMIND_CAPTURE instead of DEEPLAKE_CAPTURE at line 179 |
| refactor(cc-capture) | drop DEEPLAKE_CAPTURE fallback + remove dead homedir import |
| refactor(codex-capture) | drop DEEPLAKE_CAPTURE fallback |
| refactor(session-start-setup) | drop DEEPLAKE_WIKI_WORKER fallback |
| refactor(codex-session-start) | drop DEEPLAKE_WIKI_WORKER fallback |
| refactor(codex-session-start-setup) | drop DEEPLAKE_WIKI_WORKER / DEEPLAKE_CAPTURE fallbacks |
Bundles are rebuilt and committed alongside each source change.
Tests
All test files follow the CLAUDE.md philosophy: import and run the real module, mock only at the network / FS boundary, assert on shape AND count, cover both branches of conditional logic, and complement with bundle-level checks for the shipped artifact.
| Test file | Coverage target |
|---|---|
| summary-state.test.ts | 33 tests: bumpTotalCount / shouldTrigger boundaries / tryAcquireLock (incl. custom maxAgeMs, clock skew) / finalizeSummary / loadTriggerConfig / full cycle / cross-process race (8 subprocesses bumping + 8 racing on tryAcquireLock) |
| periodic-summary-bundles.test.ts | 15 tests: asserts the CC + Codex bundles contain the race-fix call sites and no longer contain DEEPLAKE_WIKI_WORKER / DEEPLAKE_CAPTURE |
| session-end-hook.test.ts | every branch of the hook: guard, empty session_id, null config, lock held / free, happy path, fatal catch |
| codex-stop-hook.test.ts | transcript parsing (string / array / malformed / missing / unusual content), INSERT failure swallowed, lock coordination |
| capture-hook.test.ts | event-type branches (user / tool / assistant / unknown), INSERT retry on table-missing, periodic trigger helper (every branch including release-on-spawn-failure) |
| codex-capture-hook.test.ts | codex-specific event gating + periodic trigger |
| session-start-hook.test.ts | guards + placeholder branching (exists / does not exist / capture off) + version check / autoupdate + cache cleanup |
| session-start-setup-hook.test.ts | table setup + version check + autoupdate + fatal catch |
Coverage on this PR's files
| File | Stmts | Branch | Funcs | Lines |
|---|---:|---:|---:|---:|
| src/hooks/capture.ts | 100% | 97.0% | 100% | 100% |
| src/hooks/session-end.ts | 100% | 100% | 100% | 100% |
| src/hooks/session-start.ts | 95.9% | 84.1% | 100% | 98.2% |
| src/hooks/session-start-setup.ts | 95.4% | 82.0% | 100% | 97.3% |
| src/hooks/codex/capture.ts | 100% | 93.8% | 100% | 100% |
| src/hooks/codex/stop.ts | 98.3% | 90.5% | 100% | 98.0% |
| src/hooks/codex/session-start.ts | 0% | 0% | 0% | 0% ⚠️ |
| src/hooks/codex/session-start-setup.ts | 0% | 0% | 0% | 0% ⚠️ |
Coverage for the two remaining codex session-start files is being added in follow-up commits on this branch.
Live verification
Tested against an isolated $HOME and the test_plugin org (to avoid polluting locomo_benchmark):
- CC session-end: lock free → spawns worker; lock held → logs
SessionEnd: periodic worker already running for <sid>, skippingand returns. - Codex Stop: same behavior, log in
~/.codex/hooks/deeplake-wiki.log. - Env var cleanup:
DEEPLAKE_CAPTURE=falseis ignored (capture runs);HIVEMIND_CAPTURE=falsesuppresses both capture and spawn.
Test plan
- [x]
npm run typecheckpasses - [x]
npm testpasses (21 test files, 523+ tests) - [x]
npm run buildproduces bundles that match committedbundle/contents - [x] Live-tested race fix on CC session-end and Codex Stop
- [x] Live-tested env var cleanup (new name honored, old name ignored)
- [x] CI coverage ≥ 90% on changed files (two codex session-start files still pending)
- New src/shell/grep-core.ts providing dual-table search and content normalization
- Fast-path grep now queries both memory (summaries) and sessions tables
Full changelog
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.
- Configure `HIVEMIND_SUMMARY_EVERY_N_MSGS` (default 150) and `HIVEMIND_SUMMARY_EVERY_HOURS` (default 4) as needed.
- The openclaw plugin remains unaffected – no summary feature is added.
- Periodic session summaries triggered by N events (`HIVEMIND_SUMMARY_EVERY_N_MSGS`) or H hours (`HIVEMIND_SUMMARY_EVERY_HOURS`).
- Sidecar state file `~/.claude/hooks/summary-state/.json` tracks last summary timestamp, count, and total event count.
- Shared spawn helpers reduce code duplication in capture/session-end/wiki-worker hooks.
Full changelog
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.
- DEEPLAKE_TOKEN → HIVEMIND_TOKEN
- DEEPLAKE_ORG_ID → HIVEMIND_ORG_ID
- DEEPLAKE_WORKSPACE_ID → HIVEMIND_WORKSPACE_ID
Full changelog
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
- [x]
npm test— 353 tests pass - [x]
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.
- DEEPLAKE_TOKEN → HIVEMIND_TOKEN
- DEEPLAKE_ORG_ID → HIVEMIND_ORG_ID
- DEEPLAKE_WORKSPACE_ID → HIVEMIND_WORKSPACE_ID
Full changelog
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
- [x]
npm test— 353 tests pass - [x]
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.
Fixed stray placeholder row creation when DEEPLAKE_CAPTURE=false.
Full changelog
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.
Fixed silent failure of auto‑update by reading .claude-plugin/plugin.json for version.
Full changelog
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
- [x] 534 unit tests passing
- [x] 3 new tests: verify bundles contain plugin.json read + plugin.json exists with valid semver
- [x] Tested manually from cache directory:
getInstalledVersion()returns"0.6.31"(wasnull) - [x] Verified auto-update log:
"version up to date: 0.6.31"(was silent skip)
- Removed `deeplake_sync_table()` from all hooks (11 occurrences)
- Validate git tag as semver before shell interpolation in codex auto‑update
- Escape `find -name` pattern with `sqlLike()` before SQL interpolation
- Async session startup splits initialization into sync (50 ms) and background async phases
- Direct SQL fast‑path executes a single query for every VFS read, eliminating shell processes
Full changelog
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
- [x] 531 unit tests passing (vitest), 80.6% statement coverage
- [x] 25 new
parseBashGrep()tests for all flag combinations - [x] 49 command variants tested (42 fast-path, 8 shell expected, 0 broken)
- [x] E2E tested on activeloop/hivemind (405 files) — both CC and Codex
- [x] Fresh workspace test (test_plugin/test3) — tables created correctly
- [x] Auto-update tested with version downgrade — both CC and Codex
- Validate git tag as semver before shell interpolation in codex auto-update.
- Escape `find -name` pattern with `sqlLike()` before SQL interpolation.
- Async session startup splits initialization into immediate sync phase and background async tasks, improving start‑up latency for Claude/Codex.
- All virtual filesystem read commands now execute a single direct SQL query instead of spawning Node.js shell processes, achieving up to 312× speed improvements.
Full changelog
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
- [x] 531 unit tests passing (vitest), 80.6% statement coverage
- [x] 25 new
parseBashGrep()tests for all flag combinations - [x] 49 command variants tested (42 fast-path, 8 shell expected, 0 broken)
- [x] E2E tested on activeloop/hivemind (405 files) — both CC and Codex
- [x] Fresh workspace test (test_plugin/test3) — tables created correctly
- [x] Auto-update tested with version downgrade — both CC and Codex
- Added /hivemind_capture command to enable/disable conversation capture
- Added unlinkSync to OpenClaw esbuild fs wrapper
Full changelog
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
- [x] Recall working — 5 memories recalled per turn
- [x] Capture working — openclaw sessions written to Deeplake sessions table
- [x]
/hivemind_capturetoggles capture on/off - [x] Bundle passes OpenClaw security scanner (0 flagged patterns)
- [x] Build + smoke test passes
- Added /hivemind_capture toggle for enabling/disabling capture
Full changelog
What's Changed
- Add /hivemind_capture toggle and fix Deeplake casing by @kaghni in https://github.com/activeloopai/hivemind/pull/51
Full Changelog: https://github.com/activeloopai/hivemind/compare/v0.6.27...v0.6.28
Minor fixes and improvements.
Full changelog
What's Changed
- Clean up old plugin versions from cache after auto-update by @kaghni in https://github.com/activeloopai/hivemind/pull/48
Full Changelog: https://github.com/activeloopai/hivemind/compare/v0.6.26...v0.6.27
- Logout command added
Full changelog
What's Changed
- feat: add logout command by @kaghni in https://github.com/activeloopai/hivemind/pull/46
Full Changelog: https://github.com/activeloopai/hivemind/compare/v0.6.25...v0.6.26
- openclaw login command
Full changelog
What's Changed
- Feat/openclaw login command by @kaghni in https://github.com/activeloopai/hivemind/pull/39
Full Changelog: https://github.com/activeloopai/hivemind/compare/v0.6.24...v0.6.25
Fixed MODULE_TYPELESS_PACKAGE_JSON warning.
Full changelog
What's Changed
- Fix MODULE_TYPELESS_PACKAGE_JSON warning by @kaghni in https://github.com/activeloopai/hivemind/pull/44
Full Changelog: https://github.com/activeloopai/hivemind/compare/v0.6.23...v0.6.24
Fixed listWorkspaces API to return an object with a data property containing the array.
Full changelog
What's Changed
- fix: listWorkspaces — API returns {data:[...]} not plain array by @kaghni in https://github.com/activeloopai/hivemind/pull/43
Full Changelog: https://github.com/activeloopai/hivemind/compare/v0.6.22...v0.6.23
Routine maintenance release for Hivemind turns agent traces into skills and shares with your team.
Changelog
Full Changelog: https://github.com/activeloopai/hivemind/compare/v0.6.21...v0.6.22
Fixed codex auto‑update install path and added bash‑only usage guidance.
Full changelog
What's Changed
- fix: codex auto-update install path and add bash-only guidance to SKI… by @kaghni in https://github.com/activeloopai/hivemind/pull/42
Full Changelog: https://github.com/activeloopai/hivemind/compare/v0.6.20...v0.6.21
Fixed codex auto‑update install path and updated SKILL.md bash guidance.
Full changelog
What's Changed
- fix: codex auto-update install path + SKILL.md bash guidance by @efenocchi in https://github.com/activeloopai/hivemind/pull/41
Full Changelog: https://github.com/activeloopai/hivemind/compare/v0.6.19...v0.6.20
Fixed CLI handoff issues and improved auto‑update version discovery.
Full changelog
What's Changed
- fix: improve CLI handoff and fix auto-update version discovery by @efenocchi in https://github.com/activeloopai/hivemind/pull/40
Full Changelog: https://github.com/activeloopai/hivemind/compare/v0.6.18...v0.6.19
Routine maintenance release for Hivemind turns agent traces into skills and shares with your team.
Changelog
Full Changelog: https://github.com/activeloopai/hivemind/compare/v0.6.17...v0.6.18
Routine maintenance release for Hivemind turns agent traces into skills and shares with your team.
Changelog
Full Changelog: https://github.com/activeloopai/hivemind/compare/v0.6.16...v0.6.17
Routine maintenance release for Hivemind turns agent traces into skills and shares with your team.
Changelog
Full Changelog: https://github.com/activeloopai/hivemind/compare/v0.6.15...v0.6.16
Routine maintenance release for Hivemind turns agent traces into skills and shares with your team.
Changelog
Full Changelog: https://github.com/activeloopai/hivemind/compare/v0.6.14...v0.6.15
Routine maintenance release for Hivemind turns agent traces into skills and shares with your team.
Changelog
Full Changelog: https://github.com/activeloopai/hivemind/compare/v0.6.13...v0.6.14
Routine maintenance release for Hivemind turns agent traces into skills and shares with your team.
Changelog
Full Changelog: https://github.com/activeloopai/hivemind/compare/v0.6.12...v0.6.13
- Add Codex CLI plugin support
Full changelog
What's Changed
- Add Codex CLI plugin support by @efenocchi in https://github.com/activeloopai/hivemind/pull/38
Full Changelog: https://github.com/activeloopai/hivemind/compare/v0.6.11...v0.6.12
- Explicit UTC suffix added to log timestamps
Full changelog
What's Changed
- Add explicit UTC suffix to log timestamps by @efenocchi in https://github.com/activeloopai/hivemind/pull/36
Full Changelog: https://github.com/activeloopai/hivemind/compare/v0.6.10...v0.6.11
Routine maintenance release for Hivemind turns agent traces into skills and shares with your team.
Changelog
Full Changelog: https://github.com/activeloopai/hivemind/compare/v0.6.9...v0.6.10
- Session prune command added
Full changelog
What's Changed
- Add session prune command by @efenocchi in https://github.com/activeloopai/hivemind/pull/35
Full Changelog: https://github.com/activeloopai/hivemind/compare/v0.6.8...v0.6.9
- Removed BYTEA column from schema
- Added Conversation links to index.md
Full changelog
What's Changed
- Remove BYTEA column, add Conversation links to index.md by @efenocchi in https://github.com/activeloopai/hivemind/pull/33
Full Changelog: https://github.com/activeloopai/hivemind/compare/v0.6.7...v0.6.8
Fixed regressions causing incorrect auto‑update behavior, version display issues, and missing organization data after login.
Full changelog
What's Changed
- Fix rename regressions: auto-update, version display, org after login by @kaghni in https://github.com/activeloopai/hivemind/pull/32
Full Changelog: https://github.com/activeloopai/hivemind/compare/v0.6.6...v0.6.7
Minor fixes and improvements.
Full changelog
What's Changed
- Redesign README — logo, badges, structured install by @kaghni in https://github.com/activeloopai/hivemind/pull/30
Full Changelog: https://github.com/activeloopai/hivemind/compare/v0.6.5...v0.6.6
- Added retry mechanism
- Implemented concurrency control
- Introduced parallel database optimizations
Full changelog
What's Changed
- feat: retry, concurrency control, and parallel DB optimizations by @khustup2 in https://github.com/activeloopai/hivemind/pull/29
New Contributors
- @khustup2 made their first contribution in https://github.com/activeloopai/hivemind/pull/29
Full Changelog: https://github.com/activeloopai/hivemind/compare/v0.6.4...v0.6.5
Routine maintenance release for Hivemind turns agent traces into skills and shares with your team.
Changelog
Full Changelog: https://github.com/activeloopai/hivemind/compare/v0.6.3...v0.6.4
Routine maintenance release for Hivemind turns agent traces into skills and shares with your team.
Changelog
Full Changelog: https://github.com/activeloopai/hivemind/compare/v0.6.2...v0.6.3
Minor fixes and improvements.
Full changelog
What's Changed
- Monorepo by @kaghni in https://github.com/activeloopai/hivemind/pull/27
- Fix README: remove merge conflict markers, update title to Hivemind by @kaghni in https://github.com/activeloopai/hivemind/pull/28
Full Changelog: https://github.com/activeloopai/hivemind/compare/v0.6.1...v0.6.2
- Project restructured into a monorepo with shared src/ and separate claude-code/ and openclaw/ packages
Full changelog
What's Changed
- Restructure into monorepo: shared src/, claude-code/, openclaw/ by @kaghni in https://github.com/activeloopai/deeplake-claude-code-plugins/pull/26
Full Changelog: https://github.com/activeloopai/deeplake-claude-code-plugins/compare/v0.5.10...v0.6.1
Fixes org command syntax by separating arguments and prompting for role before inviting.
Full changelog
What's Changed
- Fix org command syntax: separate args, ask role before invite by @kaghni in https://github.com/activeloopai/deeplake-claude-code-plugins/pull/24
Full Changelog: https://github.com/activeloopai/deeplake-claude-code-plugins/compare/v0.5.9...v0.5.10
Fixed capture table fallback handling and renamed schema columns.
Full changelog
What's Changed
- fix: capture table fallback + schema column renames by @efenocchi in https://github.com/activeloopai/deeplake-claude-code-plugins/pull/25
Full Changelog: https://github.com/activeloopai/deeplake-claude-code-plugins/compare/v0.5.8...v0.5.9
Routine maintenance release for Hivemind turns agent traces into skills and shares with your team.
Full changelog
Full Changelog: https://github.com/activeloopai/deeplake-claude-code-plugins/compare/v0.5.7...v0.5.8
Routine maintenance release for Hivemind turns agent traces into skills and shares with your team.
Full changelog
Full Changelog: https://github.com/activeloopai/deeplake-claude-code-plugins/compare/v0.5.6...v0.5.7
Routine maintenance release for Hivemind turns agent traces into skills and shares with your team.
Full changelog
Full Changelog: https://github.com/activeloopai/deeplake-claude-code-plugins/compare/v0.5.4...v0.5.6
Routine maintenance release for Hivemind turns agent traces into skills and shares with your team.
Full changelog
Full Changelog: https://github.com/activeloopai/deeplake-claude-code-plugins/compare/v0.5.2...v0.5.4
Routine maintenance release for Hivemind turns agent traces into skills and shares with your team.
Full changelog
Full Changelog: https://github.com/activeloopai/deeplake-claude-code-plugins/compare/v0.4.4...v0.5.2
- Plugin autoupdate triggered automatically on session start
Full changelog
What's Changed
- feat: plugin autoupdate on session start by @efenocchi in https://github.com/activeloopai/deeplake-claude-code-plugins/pull/23
Full Changelog: https://github.com/activeloopai/deeplake-claude-code-plugins/compare/v0.4.9...v0.4.4
Routine maintenance release for Hivemind turns agent traces into skills and shares with your team.
Full changelog
Full Changelog: https://github.com/activeloopai/deeplake-claude-code-plugins/compare/v0.4.7...v0.4.9
Routine maintenance release for Hivemind turns agent traces into skills and shares with your team.
Full changelog
Full Changelog: https://github.com/activeloopai/deeplake-claude-code-plugins/compare/v0.4.5...v0.4.7
Routine maintenance release for Hivemind turns agent traces into skills and shares with your team.
Full changelog
Full Changelog: https://github.com/activeloopai/deeplake-claude-code-plugins/compare/v0.4.3...v0.4.5
Routine maintenance release for Hivemind turns agent traces into skills and shares with your team.
Full changelog
Full Changelog: https://github.com/activeloopai/deeplake-claude-code-plugins/compare/v0.4.1...v0.4.3
- Separate sessions table with per-event rows
Full changelog
What's Changed
- feat: separate sessions table with per-event rows by @efenocchi in https://github.com/activeloopai/deeplake-claude-code-plugins/pull/22
Full Changelog: https://github.com/activeloopai/deeplake-claude-code-plugins/compare/v0.3.8...v0.4.1
Routine maintenance release for Hivemind turns agent traces into skills and shares with your team.
Full changelog
Full Changelog: https://github.com/activeloopai/deeplake-claude-code-plugins/compare/v0.3.7...v0.3.8
Routine maintenance release for Hivemind turns agent traces into skills and shares with your team.
Full changelog
Full Changelog: https://github.com/activeloopai/deeplake-claude-code-plugins/compare/v0.3.6...v0.3.7
Routine maintenance release for Hivemind turns agent traces into skills and shares with your team.
Full changelog
Full Changelog: https://github.com/activeloopai/deeplake-claude-code-plugins/compare/v0.3.5...v0.3.6
Fixed the update command to refresh the marketplace cache prior to updating.
Full changelog
What's Changed
- Fix update command: refresh marketplace cache before updating by @kaghni in https://github.com/activeloopai/deeplake-claude-code-plugins/pull/21
Full Changelog: https://github.com/activeloopai/deeplake-claude-code-plugins/compare/v0.3.4...v0.3.5
- Added `/deeplake-hivemind:update` command
Full changelog
What's Changed
- Add /deeplake-hivemind:update command, fix welcome message by @kaghni in https://github.com/activeloopai/deeplake-claude-code-plugins/pull/20
Full Changelog: https://github.com/activeloopai/deeplake-claude-code-plugins/compare/v0.3.3...v0.3.4
Minor fixes and improvements.
Full changelog
What's Changed
- Align README tables and architecture diagram, add release workflow, u… by @kaghni in https://github.com/activeloopai/deeplake-claude-code-plugins/pull/18
Full Changelog: https://github.com/activeloopai/deeplake-claude-code-plugins/compare/v0.3.2...v0.3.3
- Per‑user summary paths introduced.
- Unified userName resolution across the system.
Full changelog
What's Changed
- Welcome message, login command, fix hallucinated names by @kaghni in https://github.com/activeloopai/deeplake-claude-code-plugins/pull/15
- Per-user summary paths and unified userName resolution by @efenocchi in https://github.com/activeloopai/deeplake-claude-code-plugins/pull/17
Full Changelog: https://github.com/activeloopai/deeplake-claude-code-plugins/compare/v0.3.1...v0.3.2
Minor fixes and improvements.
Full changelog
What's Changed
- Update version to 0.3.1 and modify date handling in DeeplakeFs to ret… by @efenocchi in https://github.com/activeloopai/deeplake-claude-code-plugins/pull/16
Full Changelog: https://github.com/activeloopai/deeplake-claude-code-plugins/compare/v0.3.0...v0.3.1
- SessionStart now non‑blocking
- Redundant skill removed
Full changelog
What's Changed
- Non-blocking SessionStart, remove redundant skill, auth to stderr by @kaghni in https://github.com/activeloopai/deeplake-claude-code-plugins/pull/13
- Feature/improve knowledge by @efenocchi in https://github.com/activeloopai/deeplake-claude-code-plugins/pull/14
Full Changelog: https://github.com/activeloopai/deeplake-claude-code-plugins/compare/v0.2.0...v0.3.0
- Removed WASM support, retained ManagedClient SQL path
Full changelog
What's Changed
- Fix plugin install: remove duplicate hooks reference by @kaghni in https://github.com/activeloopai/deeplake-claude-code-plugins/pull/7
- Remove WASM, keep ManagedClient SQL path by @kaghni in https://github.com/activeloopai/deeplake-claude-code-plugins/pull/6
- Check in bundle/ so plugin works without build step by @kaghni in https://github.com/activeloopai/deeplake-claude-code-plugins/pull/8
- Fix/plugin install duplicate hooks by @kaghni in https://github.com/activeloopai/deeplake-claude-code-plugins/pull/9
- Fix SSO login in hook context: auth output to stderr, JSON to stdout by @kaghni in https://github.com/activeloopai/deeplake-claude-code-plugins/pull/10
- Add 120s timeout for SessionStart hook (SSO login needs time) by @kaghni in https://github.com/activeloopai/deeplake-claude-code-plugins/pull/11
- Fix/insert by @efenocchi in https://github.com/activeloopai/deeplake-claude-code-plugins/pull/12
Full Changelog: https://github.com/activeloopai/deeplake-claude-code-plugins/compare/v0.1.0...v0.2.0
- Enriched capture feature
- Integrate hook feature
- End‑to‑end test (e2e) feature
Full changelog
What's Changed
- Feature/enriched capture by @kaghni in https://github.com/activeloopai/deeplake-claude-code-plugins/pull/2
- Feature/integrate hook by @kaghni in https://github.com/activeloopai/deeplake-claude-code-plugins/pull/3
- Feature/e2e test by @efenocchi in https://github.com/activeloopai/deeplake-claude-code-plugins/pull/5
- Feature/js sdk integration by @kaghni in https://github.com/activeloopai/deeplake-claude-code-plugins/pull/4
New Contributors
- @kaghni made their first contribution in https://github.com/activeloopai/deeplake-claude-code-plugins/pull/2
- @efenocchi made their first contribution in https://github.com/activeloopai/deeplake-claude-code-plugins/pull/5
Full Changelog: https://github.com/activeloopai/deeplake-claude-code-plugins/commits/v0.1.0