Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
fbdc2fb
Add agent column to sessions and memory tables
efenocchi Apr 11, 2026
37a1988
Remove deeplake-cli reference from auth module
efenocchi Apr 11, 2026
15da887
Suppress startup messages in one-shot shell mode
efenocchi Apr 11, 2026
2f9ab11
Clean up pre-tool-use hook description text
efenocchi Apr 11, 2026
3cde615
Add codex hook source files
efenocchi Apr 11, 2026
847e80b
Add codex build targets to esbuild config
efenocchi Apr 11, 2026
28f18a2
Add codex plugin config, hooks, and install scripts
efenocchi Apr 11, 2026
2ee2c32
Add codex compiled bundles
efenocchi Apr 11, 2026
b0b8d3a
Add codex integration and hook tests
efenocchi Apr 11, 2026
0f0fb87
Add deeplake-api unit tests
efenocchi Apr 11, 2026
0f6f62f
Rebuild claude-code bundles
efenocchi Apr 11, 2026
3ac093e
Add codex plugin to marketplace manifest
efenocchi Apr 11, 2026
8f9d36c
Remove CLAUDE.md from version control
efenocchi Apr 11, 2026
20a41c0
Update package name in lockfile to hivemind
efenocchi Apr 11, 2026
98c4005
Add Codex quick start section to README
efenocchi Apr 11, 2026
9efdaa9
Merge remote-tracking branch 'origin/main' into feature/codex-impleme…
efenocchi Apr 11, 2026
e009911
Fix codex session-start test for CI without credentials
efenocchi Apr 11, 2026
aaa8da3
Use sqlStr() for JSONB values in codex capture and stop hooks
efenocchi Apr 11, 2026
1e4b756
Harden isSafe() and grep LIKE queries in both hooks
efenocchi Apr 11, 2026
ba8495a
Rebuild bundles with review fixes
efenocchi Apr 11, 2026
fbe891d
Address review feedback: sqlLike for ls, E-prefix in wiki query, pin …
efenocchi Apr 11, 2026
412a2e2
Rebuild bundles with second round of review fixes
efenocchi Apr 11, 2026
256e8cb
Add Codex fetch-and-follow install pattern to README
efenocchi Apr 11, 2026
1474abc
Remove codex/CONCERNS.md, install.sh, and hivemind-codex marketplace …
efenocchi Apr 11, 2026
83afd0c
Sync codex/package.json version to 0.6.11
efenocchi Apr 11, 2026
3286d2f
Treat newlines as command separators in isSafe()
efenocchi Apr 11, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -8,3 +8,4 @@ tmp/
coverage/
bench/
.claude/
CLAUDE.md
65 changes: 0 additions & 65 deletions CLAUDE.md

This file was deleted.

44 changes: 41 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@
|-----------------|----------------|------------------------------------------------------------|
| **Claude Code** | ✅ Stable | See [Quick start](#quick-start-claude-code) |
| **OpenClaw** | 🔧 Beta | See [Quick start](#quick-start-openclaw) |
| **Codex** | 🔜 Coming soon | — |
| **Codex** | 🔧 Beta | See [Quick start](#quick-start-codex) |

## Quick start (Claude Code)

Expand Down Expand Up @@ -85,6 +85,44 @@ openclaw plugins install hivemind

Send a message. The plugin sends you an auth link. Click, sign in, done.

## Quick start (Codex)

Tell Codex to fetch and follow the install instructions:

```
Fetch and follow instructions from https://raw.githubusercontent.com/activeloopai/hivemind/main/codex/INSTALL.md
```

Or install manually:

```bash
git clone https://github.com/activeloopai/hivemind.git ~/.codex/hivemind
~/.codex/hivemind/codex/install.sh
```

Restart Codex (quit and relaunch the CLI) to activate.

Log in when prompted, or run manually:

```bash
node ~/.codex/hivemind/codex/bundle/commands/auth-login.js login
```

### Updating

```bash
cd ~/.codex/hivemind && git pull
```

Hooks and skills update instantly — restart Codex to apply.

### Uninstalling

```bash
rm -f ~/.codex/hooks.json ~/.agents/skills/hivemind-memory
rm -rf ~/.codex/hivemind
```

## How it works

```
Expand Down Expand Up @@ -194,7 +232,7 @@ hivemind/
├── src/ ← shared core (API client, auth, config, SQL utils)
├── claude-code/ ← Claude Code plugin (hooks, virtual FS, shell)
├── openclaw/ ← OpenClaw plugin (auto-recall, auto-capture)
└── codex/ ← coming soon
└── codex/ ← Codex CLI plugin (hooks, block+inject interception)
```

## Security
Expand All @@ -211,7 +249,7 @@ hivemind/
git clone https://github.com/activeloopai/hivemind.git
cd hivemind
npm install
npm run build # tsc + esbuild → claude-code/bundle/ + openclaw/dist/
npm run build # tsc + esbuild → claude-code/bundle/ + codex/bundle/ + openclaw/dist/
npm test # vitest
```

Expand Down
14 changes: 3 additions & 11 deletions claude-code/bundle/capture.js
Original file line number Diff line number Diff line change
Expand Up @@ -257,24 +257,16 @@ var DeeplakeApi = class {
const tables = await this.listTables();
if (!tables.includes(tbl)) {
log2(`table "${tbl}" not found, creating`);
await this.query(`CREATE TABLE IF NOT EXISTS "${tbl}" (id TEXT NOT NULL DEFAULT '', path TEXT NOT NULL DEFAULT '', filename TEXT NOT NULL DEFAULT '', summary TEXT NOT NULL DEFAULT '', author TEXT NOT NULL DEFAULT '', mime_type TEXT NOT NULL DEFAULT 'text/plain', size_bytes BIGINT NOT NULL DEFAULT 0, project TEXT NOT NULL DEFAULT '', description TEXT NOT NULL DEFAULT '', creation_date TEXT NOT NULL DEFAULT '', last_update_date TEXT NOT NULL DEFAULT '') USING deeplake`);
await this.query(`CREATE TABLE IF NOT EXISTS "${tbl}" (id TEXT NOT NULL DEFAULT '', path TEXT NOT NULL DEFAULT '', filename TEXT NOT NULL DEFAULT '', summary TEXT NOT NULL DEFAULT '', author TEXT NOT NULL DEFAULT '', mime_type TEXT NOT NULL DEFAULT 'text/plain', size_bytes BIGINT NOT NULL DEFAULT 0, project TEXT NOT NULL DEFAULT '', description TEXT NOT NULL DEFAULT '', agent TEXT NOT NULL DEFAULT '', creation_date TEXT NOT NULL DEFAULT '', last_update_date TEXT NOT NULL DEFAULT '') USING deeplake`);
log2(`table "${tbl}" created`);
} else {
for (const col of ["project", "description", "creation_date", "last_update_date", "author"]) {
try {
await this.query(`ALTER TABLE "${tbl}" ADD COLUMN ${col} TEXT NOT NULL DEFAULT ''`);
log2(`added column "${col}" to "${tbl}"`);
} catch {
}
}
}
}
/** Create the sessions table (uses JSONB for message since every row is a JSON event). */
async ensureSessionsTable(name) {
const tables = await this.listTables();
if (!tables.includes(name)) {
log2(`table "${name}" not found, creating`);
await this.query(`CREATE TABLE IF NOT EXISTS "${name}" (id TEXT NOT NULL DEFAULT '', path TEXT NOT NULL DEFAULT '', filename TEXT NOT NULL DEFAULT '', message JSONB, author TEXT NOT NULL DEFAULT '', mime_type TEXT NOT NULL DEFAULT 'application/json', size_bytes BIGINT NOT NULL DEFAULT 0, project TEXT NOT NULL DEFAULT '', description TEXT NOT NULL DEFAULT '', creation_date TEXT NOT NULL DEFAULT '', last_update_date TEXT NOT NULL DEFAULT '') USING deeplake`);
await this.query(`CREATE TABLE IF NOT EXISTS "${name}" (id TEXT NOT NULL DEFAULT '', path TEXT NOT NULL DEFAULT '', filename TEXT NOT NULL DEFAULT '', message JSONB, author TEXT NOT NULL DEFAULT '', mime_type TEXT NOT NULL DEFAULT 'application/json', size_bytes BIGINT NOT NULL DEFAULT 0, project TEXT NOT NULL DEFAULT '', description TEXT NOT NULL DEFAULT '', agent TEXT NOT NULL DEFAULT '', creation_date TEXT NOT NULL DEFAULT '', last_update_date TEXT NOT NULL DEFAULT '') USING deeplake`);
log2(`table "${name}" created`);
}
}
Expand Down Expand Up @@ -350,7 +342,7 @@ async function main() {
const projectName = (input.cwd ?? "").split("/").pop() || "unknown";
const filename = sessionPath.split("/").pop() ?? "";
const jsonForSql = line.replace(/'/g, "''");
const insertSql = `INSERT INTO "${sessionsTable}" (id, path, filename, message, author, size_bytes, project, description, creation_date, last_update_date) VALUES ('${crypto.randomUUID()}', '${sqlStr(sessionPath)}', '${sqlStr(filename)}', '${jsonForSql}'::jsonb, '${sqlStr(config.userName)}', ${Buffer.byteLength(line, "utf-8")}, '${sqlStr(projectName)}', '${sqlStr(input.hook_event_name ?? "")}', '${ts}', '${ts}')`;
const insertSql = `INSERT INTO "${sessionsTable}" (id, path, filename, message, author, size_bytes, project, description, agent, creation_date, last_update_date) VALUES ('${crypto.randomUUID()}', '${sqlStr(sessionPath)}', '${sqlStr(filename)}', '${jsonForSql}'::jsonb, '${sqlStr(config.userName)}', ${Buffer.byteLength(line, "utf-8")}, '${sqlStr(projectName)}', '${sqlStr(input.hook_event_name ?? "")}', 'claude_code', '${ts}', '${ts}')`;
try {
await api.query(insertSql);
} catch (e) {
Expand Down
12 changes: 2 additions & 10 deletions claude-code/bundle/commands/auth-login.js
Original file line number Diff line number Diff line change
Expand Up @@ -433,24 +433,16 @@ var DeeplakeApi = class {
const tables = await this.listTables();
if (!tables.includes(tbl)) {
log2(`table "${tbl}" not found, creating`);
await this.query(`CREATE TABLE IF NOT EXISTS "${tbl}" (id TEXT NOT NULL DEFAULT '', path TEXT NOT NULL DEFAULT '', filename TEXT NOT NULL DEFAULT '', summary TEXT NOT NULL DEFAULT '', author TEXT NOT NULL DEFAULT '', mime_type TEXT NOT NULL DEFAULT 'text/plain', size_bytes BIGINT NOT NULL DEFAULT 0, project TEXT NOT NULL DEFAULT '', description TEXT NOT NULL DEFAULT '', creation_date TEXT NOT NULL DEFAULT '', last_update_date TEXT NOT NULL DEFAULT '') USING deeplake`);
await this.query(`CREATE TABLE IF NOT EXISTS "${tbl}" (id TEXT NOT NULL DEFAULT '', path TEXT NOT NULL DEFAULT '', filename TEXT NOT NULL DEFAULT '', summary TEXT NOT NULL DEFAULT '', author TEXT NOT NULL DEFAULT '', mime_type TEXT NOT NULL DEFAULT 'text/plain', size_bytes BIGINT NOT NULL DEFAULT 0, project TEXT NOT NULL DEFAULT '', description TEXT NOT NULL DEFAULT '', agent TEXT NOT NULL DEFAULT '', creation_date TEXT NOT NULL DEFAULT '', last_update_date TEXT NOT NULL DEFAULT '') USING deeplake`);
log2(`table "${tbl}" created`);
} else {
for (const col of ["project", "description", "creation_date", "last_update_date", "author"]) {
try {
await this.query(`ALTER TABLE "${tbl}" ADD COLUMN ${col} TEXT NOT NULL DEFAULT ''`);
log2(`added column "${col}" to "${tbl}"`);
} catch {
}
}
}
}
/** Create the sessions table (uses JSONB for message since every row is a JSON event). */
async ensureSessionsTable(name) {
const tables = await this.listTables();
if (!tables.includes(name)) {
log2(`table "${name}" not found, creating`);
await this.query(`CREATE TABLE IF NOT EXISTS "${name}" (id TEXT NOT NULL DEFAULT '', path TEXT NOT NULL DEFAULT '', filename TEXT NOT NULL DEFAULT '', message JSONB, author TEXT NOT NULL DEFAULT '', mime_type TEXT NOT NULL DEFAULT 'application/json', size_bytes BIGINT NOT NULL DEFAULT 0, project TEXT NOT NULL DEFAULT '', description TEXT NOT NULL DEFAULT '', creation_date TEXT NOT NULL DEFAULT '', last_update_date TEXT NOT NULL DEFAULT '') USING deeplake`);
await this.query(`CREATE TABLE IF NOT EXISTS "${name}" (id TEXT NOT NULL DEFAULT '', path TEXT NOT NULL DEFAULT '', filename TEXT NOT NULL DEFAULT '', message JSONB, author TEXT NOT NULL DEFAULT '', mime_type TEXT NOT NULL DEFAULT 'application/json', size_bytes BIGINT NOT NULL DEFAULT 0, project TEXT NOT NULL DEFAULT '', description TEXT NOT NULL DEFAULT '', agent TEXT NOT NULL DEFAULT '', creation_date TEXT NOT NULL DEFAULT '', last_update_date TEXT NOT NULL DEFAULT '') USING deeplake`);
log2(`table "${name}" created`);
}
}
Expand Down
Loading
Loading