# How do I use jevmem in Claude Desktop?

Run `jevmem init --tool claude-desktop` in your project and paste the config snippet it prints into Claude Desktop's `claude_desktop_config.json`: that starts jevmem's MCP server for that one project, and jevmem then saves a line when you ask Claude to call `add_memory` and looks lines up when you ask for `search_memory`.

Last updated: 2026-10-04 · jevmem 0.6.4 · [Install](https://avinash-jetwani.github.io/jevmem/install/) · [Source on GitHub](https://github.com/Avinash-jetwani/jevmem)

Nothing is automatic in Claude Desktop: it has no hook and no rule file, so jevmem acts only when you ask. A line added this way goes through the same check as a Claude Code turn: on 66 held-out turns that check was right on save or skip for 98.5% (jevmem 0.6.0, one run on 2026-09-30, [results](https://github.com/Avinash-jetwani/jevmem/blob/main/results/eval-heldout-2026-09-30-v060.json)). Those turns were given to the decider directly; nothing has been measured inside Claude Desktop.

## Set it up

1. Install the CLI:
   ```bash
   npm install -g jevmem
   ```
2. In your project's folder:
   ```bash
   jevmem init --tool claude-desktop
   ```
3. Paste the snippet it prints into the config file named below, with your [TypeSafe API key](https://console.typesafe.ai/keys) in its `env`, and restart Claude Desktop.

Every install path: [install](https://avinash-jetwani.github.io/jevmem/install/).

## The MCP config

`~/Library/Application Support/Claude/claude_desktop_config.json` (macOS) or `%APPDATA%\Claude\claude_desktop_config.json` (Windows). Claude Desktop does not inherit your shell and has no project directory, so name the project with `--root` and give the key explicitly. One config entry serves one project:

```json
{
  "mcpServers": {
    "jevmem": {
      "command": "npx",
      "args": ["-y", "jevmem", "mcp", "--root", "/absolute/path/to/your-project"],
      "env": { "TYPESAFE_API_KEY": "<your TypeSafe API key>" }
    }
  }
}
```

## What Claude can call

`jevmem mcp` starts a stdio MCP server with four tools:

| Tool | Args | Jev calls | Annotations (readOnly / destructive / idempotent / openWorld) |
|---|---|---|---|
| `search_memory` | `query`, `limit?` | 1 (choice over ids + noul per candidate, + a poisoning-gate noul per unverified, unchecked candidate) | true / false / true / true |
| `add_memory` | `text`, `kind` | 1, or 2 on a borderline line (the hook's decide: scrub, then refuse injection / small talk / duplicates; Jev may correct the kind; a contradiction supersedes the old line) | false / true / false / true |
| `list_memory` | `include_superseded?` | 0, or 1 when unverified lines have no cached gate verdict (the poisoning gate alone) | true / false / true / true |
| `audit_memory` | `apply?` | ⌈memories / 60⌉ | false / true / true / true |

In a project without `jevmem.config.json` (not opted in with `jevmem enable` or `jevmem init`) every tool returns only "jevmem isn't enabled in this project: run `jevmem enable`" and does nothing else: no Jev call, no file.

`search_memory` and `list_memory` never return a line the [poisoning gate](https://github.com/Avinash-jetwani/jevmem/blob/main/SECURITY.md#memory-poisoning) withholds (they list it under `withheld` with the reason instead), and `list_memory` without a key withholds unverified lines it cannot check. Both are marked open-world because they may ask Jev.

`add_memory` takes `kind` ∈ `decision | constraint | preference | bug | architecture | todo`, and, since 0.6.0, `dead-end`: an approach that was tried and failed or was dropped. A dead-end line must say what was tried and why, and Jev decides whether it does (the dead-end noul, in the request `add_memory` already makes, at `thresholds.deadEndMin`), or it is refused ("a dead end must say why it failed or was dropped, and Jev found no reason in this line"); a line Jev reads as a dead end with no reason keeps the kind you gave. A retry of a saved dead end that failed again for the reason that line gives is refused ("a retry that failed again adds nothing"); for a new reason, the saved line is the old line's reason followed by "retried:" and yours, and it replaces the old line ([Dead ends](https://github.com/Avinash-jetwani/jevmem/blob/main/docs/dead-ends.md#when-it-is-tried-again)). `search_memory` and `list_memory` return dead ends with `"kind": "dead-end"`; the Claude Code hook injects them as `Already tried: <line>` ([Dead ends](https://github.com/Avinash-jetwani/jevmem/blob/main/docs/dead-ends.md)).

Both writing tools are marked destructive because they can change existing lines, not only add new ones: `add_memory` re-tags a contradicted memory `[superseded]`, which takes it out of what is served (the line stays in the file), and `audit_memory` with `apply: true` sets or clears `[stale?]` flags on existing lines (flagged lines keep their text and stay live).

The `Dockerfile` at the repository root is for MCP directories that inspect a server in a sandbox (Glama builds it, starts the server and calls `tools/list`): it installs the jevmem CLI from npm and starts `jevmem mcp` on an empty folder, where the server lists its four tools and a call to one replies that jevmem isn't enabled there. It needs no key. It is not a way to run jevmem: the server works on the project it is started in.

## What is automatic in each tool

What is automatic and what depends on the agent:

| Tool | Setup | Capture | Recall |
|---|---|---|---|
| **Claude Code** | the plugin, or `jevmem init --tool claude` | **Automatic**, every turn, via the `Stop` hook | **Automatic**, every prompt, via `UserPromptSubmit` |
| **Codex** | `jevmem init --tool codex` | **Automatic while `jevmem watch` runs** (it tails Codex's session log for this project and runs the same decide → write path); otherwise agent-initiated via MCP `add_memory`, prompted by an `AGENTS.md` section | Agent-initiated: `search_memory` via MCP, prompted by `AGENTS.md` |
| **Cursor** | `jevmem init --tool cursor` | Agent-initiated: a `.cursor/rules/jevmem.mdc` rule tells the agent to call MCP `add_memory` when you state a decision. Nothing is captured if it doesn't | Agent-initiated: the rule tells it to call `search_memory` before non-trivial tasks |
| **Claude Desktop** | `jevmem init --tool claude-desktop` prints a config snippet to paste (one project per config, named with `--root`) | Manual: ask it to call `add_memory` (no hook, no rule file) | On request: `search_memory` |

MCP `add_memory` goes through the same gate as the hook. Client configs: [docs/mcp.md](https://github.com/Avinash-jetwani/jevmem/blob/main/docs/mcp.md).

## The limits, in short

- jevmem needs a TypeSafe API key ([where to get one, and the install steps](https://avinash-jetwani.github.io/jevmem/install/)).
- Message text is sent to TypeSafe to be scored, with common secrets scrubbed first ([what leaves your machine](https://avinash-jetwani.github.io/jevmem/privacy/)).
- It is automatic in Claude Code, automatic in Codex while `jevmem watch` runs, and in Cursor only when the agent calls it ([what each tool does](https://avinash-jetwani.github.io/jevmem/install/#works-with)).
- Rules every task must follow still belong in `CLAUDE.md` ([jevmem next to CLAUDE.md](https://avinash-jetwani.github.io/jevmem/compare/)).
- The guard is a backstop, not a sandbox ([what it misses](https://avinash-jetwani.github.io/jevmem/guard/#limits)).

Every limit, with the numbers: [the FAQ](https://avinash-jetwani.github.io/jevmem/faq/#what-are-jevmems-limits).
