Skip to main content

How I use Codex Memories between coding sessions

My Codex Memories config, what each setting changes, and how memory fits into a source-checked coding workflow.

CodexMemoryAI engineering

I used claude-mem (opens in a new tab) (відкриється в новій вкладці) because it removed a dull ritual from coding sessions: explaining the last session before starting the next one. Its hooks made memory feel immediate. I liked that continuity, but I did not like keeping a Claude subscription in the loop when most of my work now happens in Codex through my ChatGPT plan.

Codex Memories cannot replace claude-mem turn for turn because it works on a slower schedule. It does not save an observation after every turn. Once an earlier task has been idle long enough, Codex can extract useful material during a later root-session startup and then attempt to consolidate it into local Markdown. I use that memory for recall and keep mandatory rules in AGENTS.md and checked-in documentation. OpenAI's Memories documentation (opens in a new tab) (відкриється в новій вкладці) draws the same boundary, and the tagged pipeline documentation (opens in a new tab) (відкриється в новій вкладці) describes the two background phases.

How the local memory pipeline works

In Codex, a rollout is a saved task or thread, not an individual message. The memory pipeline runs asynchronously during a later root-session startup:

Codex local memory pipeline

A previous task becomes idle, a later root task starts the background pipeline, and Codex attempts extraction then consolidation for future tasks.

Use plus and minus to zoom, arrow keys to move around the diagram when zoomed, and Home to reset.

Phase 1 selects recent tasks once they have been idle long enough and no other worker has claimed them. For each useful task, the model produces a detailed raw memory, a compact rollout summary, and optionally a short slug. Codex redacts secrets from those generated fields and saves the result in its state database.

Phase 2 selects eligible outputs ranked by prior use and recency, then refreshes the files under $CODEX_HOME/memories/, which is ~/.codex/memories/ by default. On my machine the main workspace currently contains MEMORY.md, memory_summary.md, raw_memories.md, rollout_summaries/, and skills/. Codex generates and manages that state. I inspect the directory when I need to trace a recalled detail, but I do not hand-edit it during ordinary work.

A successful extraction may not trigger consolidation during the same startup. Phase 2 has its own coordination, retry, and cooldown checks, so a startup can finish Phase 1 and skip consolidation. The tagged Phase 2 implementation (opens in a new tab) (відкриється в новій вкладці) contains those checks.

I kept the tagged six-hour idle default. It lets memories become eligible sooner, although a comment in the tagged configuration source recommends more than 12 hours when avoiding premature extraction matters more. Memory from a finished session may still be unavailable in the next session I open five minutes later.

My exact configuration

This is the memory section in my global ~/.codex/config.toml:

~/.codex/config.tomltoml
[features]
memories = true
 
[memories]
generate_memories = true
use_memories = true
dedicated_tools = true
disable_on_external_context = false
min_rate_limit_remaining_percent = 10
min_rollout_idle_hours = 6
max_rollout_age_days = 30
max_rollouts_per_startup = 8
max_unused_days = 90

The feature flag turns the system on. generate_memories allows new tasks to become inputs for later extraction, while use_memories allows Codex to inject existing memory into future tasks. I keep both lines explicit even though they default to true in 0.145.0.

I leave extract_model and consolidation_model unset. Codex can choose the models intended for those jobs, and I have no measurement showing that an override would improve my memories.

Defaults versus my values

Setting0.145.0 defaultMineWhy I set it
dedicated_toolsfalsetrueExpose native list, search, read, and note tools
disable_on_external_contextfalsefalseKeep MCP, web, and tool-search sessions eligible
min_rate_limit_remaining_percent2510Skip fewer background passes when quota is still usable
min_rollout_idle_hours66Keep the tagged default and accept earlier extraction
max_rollout_age_days1030Give an unprocessed task more time to enter the pipeline
max_rollouts_per_startup28Let one startup pass claim up to eight candidates
max_unused_days3090Retain context for projects I revisit monthly

The tagged 0.145.0 configuration source (opens in a new tab) (відкриється в новій вкладці) defines those defaults. The current configuration reference (opens in a new tab) (відкриється в новій вкладці) now says 30 days and 16 rollouts for two of the same fields, rather than 10 and 2. I treat defaults as versioned behavior and pin the values that matter to me. If I upgrade Codex, I check the installed version and the current reference again.

Why I changed the scheduling knobs

With my configuration, a task enters the candidate pool when it is at least six hours idle and no more than 30 days old. max_rollouts_per_startup then limits Codex to eight claimed candidates during that startup pass.

Suppose I finish task A at 10:00. A new root task at noon will not select it for extraction because only two hours have passed. If I start another root task at 17:00, task A is old enough to qualify. If eight newer eligible tasks are already ahead of it, a later startup can pick it up, provided it has not aged beyond 30 days.

max_rollouts_per_startup = 8 lets one background pass process up to eight prior rollout candidates. Prompt construction is separate, so Codex does not inject all eight transcripts into every task.

max_unused_days = 90 controls how long a Phase 1 output stays eligible after Codex cites it. If Codex has never cited it, 0.145.0 uses the source task's last update time. The same setting lets startup prune stale, unselected database rows. This setting does not directly expire the generated Markdown files. I kept the longer window because I switch between projects. I accept that it may also preserve an old decision for longer. The tagged memory runtime (opens in a new tab) (відкриється в новій вкладці) contains those selection and pruning rules.

I verify the current state before relying on a memory.

A failed quota check does not block startup

min_rate_limit_remaining_percent = 10 does not reserve 10 percent of my quota. When Codex obtains a backend rate-limit snapshot, every reported primary or secondary window must clear the threshold before the memory pass starts. If Codex cannot check the snapshot, 0.145.0 still allows startup to continue. The tagged rate-limit guard (opens in a new tab) (відкриється в новій вкладці) shows that check.

I lowered the default from 25 because I prefer to run more memory passes while each reported rate-limit window remains above 10 percent. The setting cannot guarantee that the same amount remains after extraction and consolidation finish.

Tool-heavy sessions stay eligible

Most of my useful coding tasks use MCP, web search, or tool search. With disable_on_external_context = false, those tasks can still contribute to memory. Setting it to true marks the whole task polluted and excludes it from memory generation. Codex does not filter only the external snippets. The tagged external-context handling (opens in a new tab) (відкриється в новій вкладці) shows that thread-level behavior.

I keep the global value false and use /memories for exceptions. If a task is sensitive, noisy, or disposable, I can prevent that task from becoming memory input without discarding every tool-heavy session.

With this setting, external tool output can influence generated memory. OpenAI says Codex redacts secrets from generated memory fields, but also warns users not to put secrets in memory and to review the local files before sharing them.

Dedicated memory tools

With the memories feature and use_memories enabled, dedicated_tools = true adds four tools to Codex's native extension surface:

ToolWhat I use it for
memories.listBrowse the local memory workspace
memories.searchFind substring matches across memory files
memories.readRead the relevant file or line range
memories.add_ad_hoc_noteRecord an explicit remember, update, or forget request

The tagged memory-tool registry (opens in a new tab) (відкриється в новій вкладці) defines all four. They are local, namespaced Codex tools, not MCP tools. I do not install a server or manage another process.

Normally I ask in plain language:

Recall prior worktext
Search your memories for the Vercel deployment issue we solved,
then read the most relevant result.

For an explicit update:

Add a durable notetext
Remember that this repository validates MDX with bun run mdx:check.

The tool description tells Codex to use this operation only after an explicit request to remember, update, or forget something. The handler requires a timestamp-shaped Markdown filename and refuses to overwrite an existing file. It does not rewrite MEMORY.md in place. A later consolidation pass can incorporate the note. The tagged note-tool implementation (opens in a new tab) (відкриється в новій вкладці) defines the agent-facing instruction, while the local note backend (opens in a new tab) (відкриється в новій вкладці) enforces new-file creation.

The 0.145.0 configuration type includes this flag, and it works in my installed build. The public configuration reference did not list it on July 23, 2026, so I would recheck it after an upgrade rather than treat it as a permanent contract.

Memory in my workflow

I give each kind of context one home:

LayerWhat belongs there
AGENTS.md and project docsRequired commands, conventions, architecture, and review rules
Codex MemoriesPrior decisions, useful evidence, failures, preferences, and task history
SkillsRepeatable workflows such as research, review, or prose editing
MCP, apps, and live toolsCurrent external state from GitHub, calendars, deployment systems, and docs
Fresh verificationVersions, runtime output, repository state, and other facts that can drift

With this split, I am less likely to mistake a remembered preference for a repository rule or an old deployment result for current state.

At the start of a task, I let the injected memory summary provide broad context. If the request depends on an earlier decision, I ask Codex to search and read the supporting memory instead of guessing from the summary. During ordinary work, I do not create a note after every turn. I leave that volume to the background extractor.

I reserve explicit notes for facts an automatic summary might miss, such as a personal preference or a recurring failure. I also use one when a decision changes. Hard project requirements go into the repository instead.

Results so far

While writing this post, I used the injected memory to recover the Blog's earlier Humanizer workflow and bilingual parity rules. I then inspected the repository and found a route-specific end-to-end test that would fail when the new article became featured. I avoided reconstructing that context by hand and read the local Markdown to check the evidence behind the summary.

I still give up the fine-grained observation timeline I had with claude-mem. Codex memory can arrive hours later, the dedicated search is substring-based, and a 90-day consolidation window can bring back stale context. ChatGPT web memory also remains separate, so this is not one universal memory across every OpenAI surface.

I am not ready to claim a productivity percentage from this setup. I judge it by whether I spend less time reconstructing decisions and whether Codex avoids repeating failures it already solved. If old context becomes noisy, I will lower max_unused_days to 60 before adding another memory system.

Sources

5d04fb7