# How do I use jevmem in Codex?

Run `jevmem init --tool codex` in your project, then keep `jevmem watch` running while you work: `init` registers jevmem's MCP server in `~/.codex/config.toml` and adds a section to the project's `AGENTS.md`, and `watch` reads Codex's session log for the project and decides, turn by turn, what to save, as jevmem does in Claude Code.

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)

Saving is automatic in Codex only while `jevmem watch` runs; without it, a line is saved when Codex's agent calls `add_memory`. Bringing lines back is up to the agent: the `AGENTS.md` section tells it to call `search_memory`. The check behind each save is the one a Claude Code turn gets: on 66 held-out turns it 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 Codex.

## Set it up

1. Install the CLI:
   ```bash
   npm install -g jevmem
   ```
2. Save your [TypeSafe API key](https://console.typesafe.ai/keys) (paste it when asked; it isn't shown):
   ```bash
   jevmem key
   ```
3. In your project's folder:
   ```bash
   jevmem init --tool codex
   ```
   `~/.codex/config.toml` is the only file outside the project that `init` edits. It prints the file, a backup path and the exact lines before it writes, and keeps the backup.
4. While you work in Codex, keep this running in the project's folder:
   ```bash
   jevmem watch
   ```

`init` also creates `JEVMEM.md`, `jevmem.config.json` and a gitignored `.jevmem/` folder in the project. Every install path: [install](https://avinash-jetwani.github.io/jevmem/install/).

## The MCP config, if you write it yourself

`~/.codex/config.toml`:

```toml
[mcp_servers.jevmem]
command = "npx"
args = ["-y", "jevmem", "mcp"]
env = { TYPESAFE_API_KEY = "<your TypeSafe API key>" }
```

`jevmem init --tool codex` writes this section without the `env` line; the server then reads the key from `~/.jevmem/env` (jevmem does not read shell profiles). That needs jevmem 0.5.8 or later: 0.5.7's server read only its own environment, so with 0.5.7 keep the `env` line. Or from the CLI: `codex mcp add jevmem -- npx -y jevmem mcp`.

## What the agent 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).
