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.
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). Those turns were given to the decider directly; nothing has been measured inside Codex.
Set it up #
- Install the CLI:
npm install -g jevmem - Save your TypeSafe API key (paste it when asked; it isn't shown):
jevmem key - In your project's folder:
jevmem init --tool codex~/.codex/config.tomlis the only file outside the project thatinitedits. It prints the file, a backup path and the exact lines before it writes, and keeps the backup. - While you work in Codex, keep this running in the project's folder:
jevmem watch
init also creates JEVMEM.md, jevmem.config.json and a gitignored .jevmem/ folder in the project. Every install path: install.
The MCP config, if you write it yourself #
~/.codex/config.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 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). search_memory and list_memory return dead ends with "kind": "dead-end"; the Claude Code hook injects them as Already tried: <line> (Dead ends).
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.
The limits, in short #
- jevmem needs a TypeSafe API key (where to get one, and the install steps).
- Message text is sent to TypeSafe to be scored, with common secrets scrubbed first (what leaves your machine).
- It is automatic in Claude Code, automatic in Codex while
jevmem watchruns, and in Cursor only when the agent calls it (what each tool does). - Rules every task must follow still belong in
CLAUDE.md(jevmem next to CLAUDE.md). - The guard is a backstop, not a sandbox (what it misses).
Every limit, with the numbers: the FAQ.