Cross-agent persistent memory for coding assistants. Stored compressed. Retrieved fast. Local by default.
# Add to your Claude Code skills
git clone https://github.com/JuliusBrussee/cavememLast scanned: 5/21/2026
{
"issues": [
{
"type": "npm-audit",
"message": "@vitest/mocker: Vulnerability found",
"severity": "medium"
},
{
"type": "npm-audit",
"message": "esbuild: esbuild enables any website to send any requests to the development server and read the response",
"severity": "medium"
},
{
"type": "npm-audit",
"message": "vite: Vite Vulnerable to Path Traversal in Optimized Deps `.map` Handling",
"severity": "medium"
},
{
"type": "npm-audit",
"message": "vite-node: Vulnerability found",
"severity": "medium"
},
{
"type": "npm-audit",
"message": "vitest: Vulnerability found",
"severity": "medium"
}
],
"status": "PASSED",
"scannedAt": "2026-05-21T07:53:25.174Z",
"semgrepRan": false,
"npmAuditRan": true,
"pipAuditRan": true
}cavemem is an open-source ai agents skill for AI coding assistants such as Claude Code, Codex CLI, and ChatGPT, built by JuliusBrussee. Cross-agent persistent memory for coding assistants. Stored compressed. Retrieved fast. Local by default. It has 643 GitHub stars.
Yes. cavemem passed SkillsLLM's automated security scan — a dependency vulnerability audit plus prompt-injection heuristics — with no high-severity issues. You can read the full report in the Security Report section on this page.
Clone the repository with "git clone https://github.com/JuliusBrussee/cavemem" and add it to your Claude Code skills directory (see the Installation section above).
cavemem is primarily written in TypeScript. It is open-source under JuliusBrussee on GitHub, so you can review or fork the full source.
Yes. SkillsLLM lists many other AI Agents skills you can browse and compare side by side. Open the AI Agents category from the badge at the top of this page, or use the Related Skills and comparison links further down to weigh cavemem against similar tools.
No comments yet. Be the first to share your thoughts!

why agent forget when agent can remember
Install • How it works • CLI • MCP • Settings
Cross-agent persistent memory for coding assistants. Hooks fire at session boundaries, compress observations with the caveman grammar (~75% fewer prose tokens, code and paths preserved byte-for-byte), and write to local SQLite. Agents query their own history through three MCP tools. No network. No cloud.
Supports: Claude Code · OpenCode · Codex · GitHub Copilot · Augment Code · Cursor (query-only) · Gemini CLI (query-only) · Antigravity (query-only) · IBM Bob (query-only)
search, timeline, get_observations — agents filter before fetching.http://localhost:37777 for browsing sessions in human-readable form. Token-protected: the worker generates a local bearer token on first start and injects it into the served page, so cavemem viewer still opens with zero friction while /api/* rejects requests without it.<private>...</private> stripped at write boundary. Path globs exclude whole directories.npm install -g cavemem
cavemem install # Claude Code
cavemem install --ide cursor # cursor | gemini-cli | opencode | codex | copilot | augment | antigravity | bob
cavemem status # see wiring + embedding backfill
cavemem viewer # open http://127.0.0.1:37777
No daemon to start. Hooks write synchronously. A local worker auto-spawns in the background on the first hook to build embeddings and serve the viewer; it self-exits when idle (set embedding.idleShutdownMs to 0 to keep it running until killed). Disable auto-spawn — and with it the HTTP listener — with cavemem config set embedding.autoStart false.
"Query" means the MCP server can search memory captured elsewhere. "Capture" means this IDE's own sessions write new observations — without it, the DB never fills for that IDE no matter how healthy cavemem status otherwise looks (#58).
| IDE | capture (hooks) | query (MCP) | notes |
|---|---|---|---|
| Claude Code | ✓ | ✓ | 5 hooks: SessionStart, UserPromptSubmit, PostToolUse, Stop, SessionEnd |
| OpenCode | ✓ | ✓ | via bundled bridge plugin¹ |
| Codex CLI | ✓ | ✓ | no SessionEnd event² |
| GitHub Copilot | ✓ | ✓ | no SessionEnd event² |
| Augment Code | ✓ | ✓ | no UserPromptSubmit event² |
| Cursor | — | ✓ | query-only — no hooks system |
| Gemini CLI | — | ✓ | query-only — no hooks system |
| Antigravity | — | ✓ | query-only — no hooks system |
| IBM Bob | — | ✓ | query-only — no hooks system |
¹ OpenCode has no hooks.json-style event system. Capture instead goes through a bundled bridge plugin (opencodeBridge.js, symlinked into OpenCode's plugin dir on install) that subscribes to OpenCode's native event and tool.execute.after hooks and shells out to the same cavemem hook run handlers every other IDE uses — same lifecycle coverage, different wiring.
² Copilot's and Codex's hook payloads are close enough to Claude Code's shape that the same handlers are reused unmodified, but neither event set is complete: Codex and Copilot have no SessionEnd, and Augment has no UserPromptSubmit. Every other lifecycle moment still fires and gets written.
Run cavemem status after installing to see which IDEs are wired up, with query-only ones flagged inline (ides: claude-code, antigravity (query-only)).
Claude Code runs hook commands through sh -c even on Windows. If Git for Windows' Git\bin isn't
on your user Path, sh doesn't resolve, hooks fail silently, and capture quietly stops — cavemem doctor/status keep reporting healthy because the failure never reaches the CLI. Add
C:\Program Files\Git\bin (or <scoop dir>\apps\git\current\usr\bin for a Scoop install) to your
user Path, then verify with where.exe sh. cavemem doctor and cavemem install both check
sh resolvability on win32 and print a warning if it's missing.
Claude Code's hooks docs also describe a shell field ("bash" / "powershell") and a shell-free
args exec form. We looked at emitting either instead of the plain sh-shaped command string, but
held off: we can't verify those fields against every Claude Code version in the wild, and the
current command has no shell metacharacters, so it already tokenizes the same way whether Claude
Code runs it through sh or falls back to PowerShell. Once there's a way to gate on a minimum
Claude Code version, switching to the shell-free args form would drop the sh dependency
entirely.
session event → redact <private> → compress → SQLite + FTS5
↑
MCP queries on demand
What compression looks like in practice:
Input: "The auth middleware throws a 401 when the session token expires; we should add a refresh path."
Stored: "auth mw throws 401 @ session token expires. add refresh path."
Viewed: "The auth middleware throws a 401 when session token expires. Add refresh path."
Code blocks, URLs, paths, identifiers, and version numbers are never touched. Hook handlers complete in under 150ms. Full bodies fetched on demand via get_observations.
| Command | |
|---|---|
cavemem install [--ide <name>] |
Register hooks + MCP for an IDE |
cavemem uninstall [--ide <name>] |
Remove hooks + MCP |
cavemem status |
Single dashboard: wiring, DB counts, embedding backfill, worker pid |
cavemem config show|get|set|open |
View/edit settings — schema is self-documenting |
cavemem start|stop|restart |
Control the worker daemon (usually unnecessary — auto-starts) |
cavemem viewer |
Open the memory viewer in your browser |
cavemem doctor |
Verify installation |
cavemem search <query> [--limit N] [--no-semantic] |
Search memory (BM25 + cosine re-rank) |
cavemem compress <file> |
Compress a file with caveman grammar |
cavemem reindex |
Rebuild FTS5 + vector index |
cavemem export <out.jsonl> |
Dump sessions + observations to JSONL |
cavemem import <file.jsonl> [--dry-run] |
Load a JSONL export back in (merge, safe to re-run) |
cavemem mcp |
Start MCP server (stdio) |
Manual cross-device transfer: on machine A, cavemem export backup.jsonl. Copy the file to machine B, then on B, stop the worker (cavemem stop), run cavemem import backup.jsonl, and restart it (cavemem start). Records already present are skipped, and imported observations whose ids clash with different local ones get fresh ids — nothing is overwritten, and importing the same file twice is a no-op. Imported observations keep their original compressed content and get picked up by the embedding backfill like any new write — vectors themselves aren't exported.
Progressive disclosure: search and timeline return compact results; get_observations fetches full bodies.
| Tool | Returns |
|---|---|
search(query, limit?) |
[{id, score, snippet, session_id, ts}] — BM25 + optional cosine re-rank |
timeline(session_id, around_id?, limit?) |
[{id, kind, ts}] |
get_observations(ids[], expand?) |
Full bodies, expanded by default |
list_sessions(limit?) |
[{id, ide, cwd, started_at, ended_at}] |
enrich(query, note?) |
{results: [{title, url, extract, observation_id}]} — opt-in web enrichment |
enrich is off by default. When enrich.enabled is false the tool is not registered and cavemem makes no network call, ever. When enabled, it searches DuckDuckGo, stores compressed plain-text extracts as observations (tagged source: web + URL for provenance), and returns them.
<cavemem home>/settings.json, where the cavemem home directory resolves in this order:
CAVEMEM_HOME env var, if set.~/.cavemem — zero breaking change for current installs.$XDG_DATA_HOME/cavemem whenever XDG_DATA_HOME is explicitly set — on any platform,
not just Linux. Without the var, Linux uses the XDG default ~/.local/share/cavemem;
macOS/Windows k