
jevmem
io.github.Avinash-jetwaniv0.6.2Updated Sep 30, 2026
Automatic project memory for Claude Code. Also works with Cursor and Codex.
Installation
In SourceWeft
- Open jevmem in the dashboard and add it to a workspace.
- Enable the server for the chats that should use its tools.
Desktop only via STDIO. STDIO servers start a local process, so they need the SourceWeft desktop host.
Other MCP clients
Follow the launch instructions in the repository.
README
Automatic project memory for Claude Code. Also works with Cursor and Codex.
Now in Anthropic's Claude plugin directory: in the Claude app, Plugins → Discover → jevmem → Add, then follow the setup steps.
[npm version] [license] [node] [CI] [M8ven Verified]
What it does
https://github.com/user-attachments/assets/ed77849e-db1c-4c05-9ad8-4cab0b3968a2
- Saves decisions, constraints, bugs, todos and dead ends (an approach that was tried and failed, with the reason) from your Claude Code chats into
JEVMEM.md, automatically. - When you change your mind, the old line is marked superseded, not deleted.
- Next session, the relevant lines are added to Claude's context.
- Checks lines added by others before they're added to Claude's context.
- Checks Bash, Edit and Write calls against your saved rules before they run, and has Claude Code ask you when one may be broken (the guard, 0.6.0).
Real lines from 0.5.7's default writer, which 0.5.8 to 0.5.10 did not change (the run, 2026-09-26). It kept one sentence of each turn: the Postgres turn also said "SQLite locks up under concurrent writes", and that reason was left out. Since 0.6.0 the line is made from the sentences Jev picks, the one that states the memory and the one that gives its reason (What's new). With writer set, an OpenAI or Anthropic model condenses the whole turn instead.
What's new
- 0.6.2, a guard fix: 0.6.0's guard skipped a Bash call with
if [ … ],while [ … ]oruntil [ … ]in it. The check threw on the[and the hook stayed silent, so such a call ran unchecked:if [ -f x ]; then git push origin directory; figot no ask under a rule against pushing to that branch, wheretrue && git push origin directorywas asked about (Jev 0.97). Found in 0.6.0's own release session, three calls in;jevmem doctorlisted the failed checks. The shell reader now knows the shell's reserved words, a glob never throws, and a part of the check that fails is logged while the rest still decides (docs/guardrails.md). 0.6.2 is 0.6.1's code, published again: npm did not list 0.6.1 for a time after its release and a second publish was refused, so 0.6.2 went out; npm lists both now. Upgrade withnpm install -g jevmem@latest(plugin users too: the plugin runs this CLI) (CHANGELOG: 0.6.1, 0.6.2).
What's new in 0.6 (0.6.0, 2026-09-30; CHANGELOG)
- Dead ends. jevmem saves an approach that was tried and failed, with the reason, and puts it in front of Claude as "Already tried: …" when a prompt comes back to it. A later turn that shows it works now supersedes it (docs/dead-ends.md). Decide's held-out v3 set, 100 turns in five new projects, run on the release build on 2026-09-30 (first run 2026-09-27, before the writer changed): dead ends saved 25 of 25, every one with its reason (25 of 25); reversals of a saved line superseded 10 of 10 (results). In the outcome A/B below, Claude never repeated an approach recorded as failed (0 of 15 sessions), against 3 of 15 with no memory; the same lines in
CLAUDE.md: also 0 of 15. - Recall that finds the lines a prompt needs, and nothing for a prompt that needs none. Every live line is asked about, each on its own. Retrieval held-out v2: 90 prompts over three new projects of 20, 80 and 250 lines, run once on 2026-09-28, 0.6 (
48cc67d, the recall code that ships) against 0.5.9: recall 75/78 against 55/78 (18 of the 78 wanted lines are dead ends, which 0.5.9 cannot read; on the other 60, 0.6 found 57 and 0.5.9 found 55); lines injected that were wanted or fine 96/97 against 88/104; unrelated prompts that got a line 1/18 against 5/18; superseded lines injected 0 of 90 in both. Prompts that need two lines got both in 3 of 6. Cost per prompt $0.000578 against $0.000267, and $0.001002 against $0.000320 on the 250-line file. Above 250 live lines, only the 250 sharing the most words with the prompt are asked about (a 500-line dev file: recall 37/46). - A slow or failed Jev call no longer means no memory. Past one second, the prompt gets the lines that share the most words with it. On held-out v2 no call ran late (hook p95 596 ms; 0.5.9's, in the same run, 491 ms), so this served no prompt there. Word match finds lines that share the prompt's words (on dev, as if every prompt had fallen back, 25 of 32 for prompts that name what they need) and seldom the others (3 of 33).
- Claude acts on the saved line about as often as with
CLAUDE.md. "With jevmem, Claude followed the project's saved line in 66 of 72 sessions; with the same lines inCLAUDE.md, in 67 of 72; with no memory, in 28 of 72." 24 tasks in three small projects of 34 to 42 saved lines, 3 runs each, real Claude Code 2.1.281 sessions withclaude-sonnet-5; the jevmem arm on 0.6 (48cc67d, 2026-09-29, the same 66 of 72 as on part 3's build; the recall code that ships), the other two arms in part 3's run (2026-09-28).CLAUDE.mddid better where nothing in the prompt points at the line (a convention for every user-facing string: 3 of 3 against 0 of 3); rules every task must follow belong there. - The guard, a backstop. A
PreToolUsehook checks each Bash, Edit and Write call against your saved rules, and has Claude Code ask you (or blocks the call) when Jev says it may break one (docs/guardrails.md). In the A/B's 6 constraint tasks (18 sessions, rerun on the release build on 2026-09-30 with Claude Code 2.1.284), recall kept Claude from ever attempting the forbidden change (0 of 18; 10 of 18 with no memory in the 2026-09-28 run), and the guard checked all 78 of those sessions' Bash, Edit and Write calls and asked once: an edit to the output formatter that put a new format behind a new flag, as its rule allows (Jev 0.89); inclaude -pthat ask refused the edit, and the session finished the task another way, 18 of 18 followed the rule and 17 of 18 did the task (results). On the guard's second held-out set (274 calls in five new projects, written after a day's trial in jevmem's own repository; run once on the 0.6.0 build on 2026-09-30 and once on 0.6.1 the same day): violations caught 66/68 and the check that guards jevmem's own files right on 274/274 calls in both runs, and false asks 3–4 of 206 across the two (the one call that differs isgit add token.secret.example, which breaks no rule: 0.52 in the 0.6.0 run, then 0.47, either side of the 0.5 threshold; the command has no bracket, so that is Jev's variation between runs, not the fix) (docs/guardrails.md). - Background subagents. A turn that hands work to a subagent in the background is decided once, when it is over, not while the subagent works, and the subagent's report is never read as your message. Decide held-out v4: 30 real Claude Code 2.1.281 sessions, 14 with a background subagent, replayed through the release build and 0.5.9 in one run on 2026-09-30 (first run 2026-09-28): lines saved while a turn was still running 0 (0.5.9: 9), lines decided from a subagent's report read as your message 0 (0.5.9: 13), turns saved or skipped right 32 of 33 (0.5.9: 27 of 33) (results, 0.5.9). The line is the sentence that states the memory, not the request or hand-off next to it: on a line-text held-out set of 64 saved turns in four new projects (16 of them a memory next to a request or a hand-off to a subagent), run once on 2026-09-29 on the writer that ships, the saved lines stated the fact in 62 of 63 (0.5.9: 41 of 59), kept the reason in 29 of 30 (0.5.9: 5 of 25), and none was a request or a hand-off (0.5.9: 13 of 59).
Known limits in 0.6.2
- A plain statement can fall under the content threshold. A rule said without must, never or prefer ("user-facing copy is British English") can be skipped: 2 of the 12 genuine rules on the genuine-rule held-out set, in 0.5.9 too (docs/benchmark.md).
- No way to mark your own rules as verified. A line you add with
jevmem addor by hand is unverified: the poisoning gate checks it before recall serves it, and the guard asks about it but never denies on it. - A line is at most two sentences, and Jev can pick the wrong one (docs/benchmark.md). Jev picks the sentence that states the memory and the one that gives its reason; a fact told in two sentences keeps one of them, and on the line-text held-out set one rule's line was its consequence without the rule (1 of 63), and one to-do kept "don't start on it today" as its second sentence. The line comes from the text decide chose: a bug whose cause only Claude's reply found gets your description of it. When the pick request fails, the line is one sentence chosen by words, as in 0.5.9.
- A second line one line crowds out. When the first line takes the whole "most relevant" choice, a second line is kept only at relevance 0.97 or more: 3 of 6 two-line prompts on retrieval held-out v2 lost their second line.
- More than 250 live lines. Only the 250 sharing the most words with the prompt are asked about; on a 500-line dev file, 8 of 9 missed lines were never sent. Sending all of them would cost about twice as much per prompt on such a file.
- Rules every task must follow. Recall judges each line against the prompt; a convention nothing in the prompt points at belongs in
CLAUDE.md. - The guard sees the words a rule and a call share (docs/guardrails.md). A rule that names neither the tool nor the host (
psql "$PROD_WAREHOUSE_DSN"under "the production warehouse is never queried from a shell") gets no candidate, and one shared word is not enough (git tag -d v0.5.10under "never delete a tag",npm version 0.6.0under "no version bump"). - Jev reads a script's text as run. A script that runs
jevmem guard test "git push origin directory"(a dry run of the guard) is asked about under "never push to that branch by hand" (Jev 0.57 to 0.71). - An ambiguous rule gets an ambiguous answer. A
Signed-off-byunder the owner's own name scored 0.07 against "commits are under only, with no Co-Authored-By or other trailers"; write rules as you mean them.
Upgrading to 0.6.2 (0.6.1 is the same code; npm lists both). From 0.6.0, npm install -g jevmem@latest is the whole upgrade: the plugin's hooks did not change, and the directory and marketplace plugins move to 0.6.2 with the CLI. From 0.5.x, one of the paths below, tested on 2026-09-30 on the 0.6.0 build in a temporary HOME with a project set up on 0.5.10 that kept its lines (results/upgrade-2026-09-30.txt); 0.6.1 changes nothing in them:
- From the Claude plugin directory (
jevmem@synced):npm install -g jevmem@latestbrings everything the two hooks run, dead ends, the new recall, the line made from Jev's sentences, the subagent fix, andjevmem guard test, at once. The guard'sPreToolUsehook is in the 0.6.x plugin, which the directory serves after the release moves itsdirectorybranch; until your app syncs it, the new CLI runs under the two hooks of the 0.5.7 plugin and the guard is off in plugin sessions.jevmem doctorshows which plugin and CLI run. - From the jevmem marketplace (
jevmem@jevmem):npm install -g jevmem@latest, then update the plugin in Claude Code (/plugin, orclaude plugin update jevmem@jevmem); Claude Code picks up the new plugin because its version changed. With the 0.6.x plugin and an older CLI, the plugin prints one warning line and skips the guard's hook. - With
jevmem inithooks:npm install -g jevmem@latest, then runjevmem init --tool claudeagain in each project: it adds thePreToolUsehook next to the two it registered before and changes nothing else;JEVMEM.md,jevmem.config.jsonand.jevmem/are kept. Until then the two existing hooks already run the new CLI, andjevmem doctorsays the guard hook is missing. Ajevmem.config.jsonwritten by an earlier version has noguardblock and gets the defaults (askmode).
Earlier releases:
- In the Claude plugin directory (2026-09-29): add jevmem from the Claude app. The plugin runs the
jevmemCLI from npm, so setup takes three commands. - 0.5.10, clearer setup for installs from the Claude plugin directory (
jevmem@synced):jevmem keysaves your key, the first prompt says when no key is found and how to fix it,jevmem doctorsees the directory's plugin, andjevmem enablegives one next step. No change to what is saved or recalled. Upgrade withnpm install -g jevmem@latest(plugin users too: the plugin runs this CLI) (CHANGELOG). - 0.5.8, a security fix: secrets named like
PGPASSWORD=weren't scrubbed in 0.5.7 and earlier. A prompt or turn withPGPASSWORD=…,MYSQLPWD=…or"password": "…"in it was sent to TypeSafe with the value as written. Upgrade withnpm install -g jevmem@latest(plugin users too: the plugin runs this CLI), and rotate any such secrets that were in your chats in an enabled project (advisory GHSA-2r3p-5hmg-46p5, CHANGELOG). - Install as a Claude Code plugin (0.5.0), opt-in per project since 0.5.1: it does nothing until you run
jevmem enablein a repo. - A memory-poisoning check on recall (0.5.0): lines that jevmem did not write on your machine (a teammate's, a pull request's, your own hand edits) are checked by Jev before they're added to Claude's context. In our 44-line test set (2026-09-25) it blocked 20 of 22 planted lines, with 0 of 22 false blocks on legitimate rules (SECURITY.md).
- Turns queued during Jev outages (0.5.0) and retried later, in order, instead of being dropped.
jevmem import(0.5.0) for an existingCLAUDE.md,AGENTS.mdor Cursor rules.- Saving runs in the background (0.5.0): the
Stophook is async, so Claude doesn't wait for it. On v0.5.6 its process exited in 12–14 ms, and the decision was recorded 0.26–0.28 s after it started (results). - No calls to OpenAI or Anthropic unless you set
writerinjevmem.config.json(0.5.4). A key in your environment is not enough on its own. - PRIVACY.md (0.5.7): no telemetry, and exactly what goes where, with the third parties' privacy policies and how to delete your data.
Install (60 seconds)
You need a TypeSafe AI key for Jev. jevmem writes each line itself; an OpenAI or Anthropic writer is optional and off unless you set writer in jevmem.config.json (configuration).
Option 1: Claude Code plugin (recommended)
From the Claude plugin directory
This needs Claude Code 2.1.273 or later: earlier versions don't sync the plugins you add in the Claude app (Claude Code docs).
-
In the Claude app: Plugins → Discover → jevmem → Add. The app warns you before it adds the plugin; the warning is about the plugin's local MCP server,
jevmem mcp, a command the plugin runs on your computer (the CLI from step 2). -
Install the CLI the plugin runs:
-
Add your TypeSafe key (from console.typesafe.ai/keys): run this, then paste the key when it asks. It doesn't show the key as you paste, and saves it in
~/.jevmem/env, readable only by you. -
In a terminal, in your project's folder, run
jevmem enable. The plugin does nothing in a project until you do. -
Start Claude Code in that project, signed in with the same Claude account as the app. The plugin shows as
jevmem@synced(run/reload-pluginsif Claude Code asks). -
jevmem doctorchecks the setup. If Claude Code shows "jevmem: CLI not found", see if the plugin can't find the CLI.
Claude Code's own memory may also say it saved something; JEVMEM.md shows what jevmem saved.
From the jevmem marketplace
Add your key with jevmem key as in step 3 above, or enter it in Claude Code with /plugin configure jevmem, which Claude Code keeps in your system's secure credential store (the claude plugin install shell command doesn't ask for it). That setting exists only for a plugin installed from a marketplace: the directory's jevmem@synced has no Configure options.
If the plugin can't find the CLI
The plugin runs the jevmem CLI from npm, so install that first. The hooks find it on the PATH Claude Code gives them or, when that PATH lacks it (the desktop app's can), in /opt/homebrew/bin, /usr/local/bin, ~/.local/bin, ~/.volta/bin or the newest Node version under ~/.nvm. Without it, an enabled project shows "jevmem: CLI not found, so memory is off in this project" on the first prompt of each session, and the MCP server fails to start (/mcp shows it as failed). The plugin does nothing until you run jevmem enable in a project; what it runs, and how to switch it off: docs/hooks.md.
Option 2: npm (also sets up Cursor and Codex)
init creates JEVMEM.md, jevmem.config.json and .jevmem/, and registers the three Claude Code hooks (details). Hooks don't get your shell's variables and jevmem doesn't read shell profiles, so save the key with jevmem key, which puts it in ~/.jevmem/env. jevmem doctor checks the setup.
Already have a CLAUDE.md? jevmem import splits CLAUDE.md, AGENTS.md and .cursor/rules/* into statements, puts each through the same gate as a turn, and prints what it would add; --apply writes them. --from claude-auto-memory also reads Claude Code's own auto memory for the project. The source files are only read.
Works with
What is automatic and what depends on the agent:
MCP add_memory goes through the same gate as the hook. Client configs: docs/mcp.md.
How it decides
- Scrub. Common secret shapes, email addresses and card-shaped numbers are removed from the turn before it leaves your machine.
- Ask Jev typed questions. Jev by TypeSafe AI answers a fixed set of small questions with probabilities: is there a decision, a rule, a bug? is it small talk or an injection attempt? which existing line does it change?
- Apply thresholds in code. Plain rules over those probabilities decide save or skip; they live in
jevmem.config.json, not in a prompt. - Write one line. On save, jevmem writes one line of at most 200 characters from the sentences of the turn that Jev picks (the one that states the memory and the one that gives its reason), or, if you set
writerinjevmem.config.json, a small OpenAI or Anthropic model condenses the turn. - Supersede the old line. If the turn replaces an existing memory, that line is tagged
[superseded] … → id:newand stays in the file.
Tiers, questions, policy, contradictions, recall and audit: docs/how-it-works.md.
Benchmark
66 held-out turns, all seven deciders given the same state (method, regression set, pricing, p95, retries). The six LLM rows are v0.4.2's run of 2026-09-23; jevmem's row is 0.6.0's run of the same set on 2026-09-30 (results; every mode, three builds), where 0.5.9 and v0.4.2 score the same and cost less:
The 0.28 s is the Jev API decision (p95 527 ms; a saved turn's line costs one more request, $0.000159 per decision with it). Since v0.5.0 you do not wait for it: the Stop hook is async and its process exits in 12–14 ms (v0.5.6: 12 ms for the hook jevmem init registers, 14 ms for the plugin's), and the daemon records the decision 0.26–0.28 s after the hook starts (results, cost and latency).
On 66 held-out turns, jevmem 0.6.0's median decision took 0.28 s, against 2.8–4.3 s for six current LLMs. Its accuracy was within the LLMs' range: 98.5% save/skip (tied with GPT-6 Astra for highest) and 95.5% save+kind, against 90.9–98.5% for the LLMs. GPT-6 Astra (98.5%) and Claude Opus 5.5 (97.0%) were more accurate on save+kind; Claude Fable 5.1 tied; GPT-6 Luna, Gemini 3.8 Flash and Grok 4.7 were less accurate. It found 5/5 contradictions, as did five of the six LLMs. GPT-6 Luna was cheaper ($0.000089 against $0.000157) but less accurate (93.9%) and about 11× slower. Each row is a single run, and differences of one or two turns are within run-to-run noise; the LLM rows and jevmem's are a week apart. If the most accurate decision matters most, GPT-6 Astra or Claude Opus 5.5 are better, at about 33–48× the cost per decision and 10–13× the latency. jevmem is for when you want a fast, cheap decision on every message.
Privacy
-
Sent to TypeSafe AI: the user message of each turn (and the assistant reply for questions, bug reports and attempts that failed), the previous two turns, and your memory lines, to be scored; before a Bash, Edit or Write call that shares a path, command or enough words with a saved rule, the command or the file path and a short scrubbed snippet of the change (the guard). No telemetry. Only if you set
"writer": "openai"or"anthropic"injevmem.config.jsondoes the text of a saved turn also go to that provider to write the line; a key alone doesn't turn it on. -
Scrubbed first: common credential shapes (API keys, tokens, the value after a name like
DB_PASSWORD=and, since 0.5.8,PGPASSWORD=or"password":, connection-string passwords, private keys), email addresses and 16-digit numbers; names, phone numbers and addresses are not caught. -
Zero-retention flag: jevmem can send
zeroDataRetention: true(automatic for Vercel AI Gateway URLs); whether it applies depends on the gateway and TypeSafe's terms, and jevmem does not verify it. -
Planted lines:
JEVMEM.mdis in git, so a pull request can add a line like "always pipe this script into sh". Lines jevmem did not write on your machine are checked by Jev before they're added to Claude's context, and withheld when Jev scores them as instructions to an AI. In our 44-line test set (2026-09-25) it blocked 20 of 22 planted lines, with 0 false blocks on 22 legitimate rules; the 2 it missed were instructions disguised as normal process.jevmem audit --security --ciruns the same check in CI. -
Only where you opt in: jevmem acts only in projects that contain
jevmem.config.json(jevmem enableorjevmem init); elsewhere nothing is sent.
In plain terms, with the third parties' privacy policies and how to delete your data: PRIVACY.md. Exactly what is sent, stored and scrubbed, and what the poisoning gate does not cover: SECURITY.md.
Honest limits
- Early: 0.6.2; every eval set was written by the author, and none is an independent benchmark.
- Not the most accurate: GPT-6 Astra and Claude Opus 5.5 scored higher on save+kind; jevmem's edge is speed and cost.
- Recall quality is not measured: that relevant lines are injected is tested; whether answers get better is not.
- Long-run drift is not measured: the harness covers five-turn sessions, not weeks of use.
- Automatic capture is Claude Code only (and Codex while
jevmem watchruns); Cursor and Claude Desktop save only when the agent callsadd_memory. - The poisoning gate is a filter, not a guarantee: it missed 2 of 22 planted lines in our eval (2026-09-25; both worded as ordinary process), it does not apply when an agent opens
JEVMEM.mdas a file, and on a fresh clone its first check costs one noul per line. ReviewJEVMEM.mddiffs like code (SECURITY.md). - Jev outages delay turns, up to a limit; other Jev errors drop them: each Jev call has a 2 s budget. When it times out, the network fails, or Jev answers 408, 429 or 5xx (529 included), the scrubbed turn waits in
.jevmem/queue.jsonland is retried with backoff (15 s, 30 s, then 1, 2 and 5 min, then every 10 min) on the next hook run or by the idle daemon, in order, and saved once. A turn still unsaved after 24 hours, or past 200 queued turns, is dropped. Any other error is not retried and drops the turn at once: a 400 from Jev, for example, or a 401 when the key is wrong, which drops every turn until the key is fixed. Each drop leaves a line in.jevmem/log.jsonl, and the retry-queue line ofjevmem statscounts them.
Commands
These are 0.6.2's commands: 0.5.10's and jevmem guard (0.6.0). Every command accepts --help. Set JEVMEM_VERBOSE=1 for a one-line latency/cost summary after every hook run.
Links
- Docs: how it works · benchmark · cost · hooks · MCP and client configs · configuration · demo
- CHANGELOG · Releases · DECISIONS · CONTRIBUTING · SECURITY · PRIVACY
- License: MIT
Source: README.md at commit c1f4ea8
Tools
0Version history
1- v0.6.2LatestSep 30, 2026

