Environment: Codex Desktop on macOS, CLI 0.146.0, [features] memories = true
Summary
Background memory generation (memory_stage1) submits entire session transcripts to a
model with no size ceiling. On large transcripts this reliably fails with a context-window
error after ingesting the input — consuming quota and producing nothing. Separately, the
shipped defaults allow generation to keep running until only 25% of the plan's quota
remains, and route extraction through whatever model the user selected for interactive
work.
Three distinct problems, in descending order of severity.
1. No per-transcript size cap → repeated context-window failures
memories_1.sqlite on this machine:
memory_stage1 done 165
memory_stage1 error 11
All 11 failures share the same error, with retries exhausted:
last_error: "Codex ran out of room in the model's context window.
Start a new thread or clear earlier history before retrying."
retry_remaining: 0
Failed jobs are dramatically larger than successful ones:
|
n |
median |
mean |
max |
| Errored |
11 |
3,450,252 B |
13,182,226 B |
66,822,293 B |
| Succeeded |
165 |
492,898 B |
1,723,614 B |
30,446,821 B |
Because retry_remaining reached 0, each of these oversized transcripts was submitted
multiple times, filling a context window and failing on every attempt.
The available settings limit how many rollouts (max_rollouts_per_startup), how
old they may be (max_rollout_age_days), and how much quota must remain
(min_rate_limit_remaining_percent) — but there is no max_rollout_bytes equivalent. A
single oversized transcript is still submitted whole.
Compounding factor: transcripts are mostly non-text payloads. Composition of the
66.8 MB rollout above, all 111 lines of it:
| Payload type |
items |
bytes |
share |
image_generation_end |
7 |
19,185,819 |
28.7% |
image_generation_call |
7 |
19,184,741 |
28.7% |
function_call_output |
12 |
16,961,978 |
25.4% |
message |
21 |
11,407,036 |
17.1% |
| reasoning / token_count / meta |
32 |
~67,000 |
0.1% |
57.4% is base64 image data — seven generated images, embedded twice each — submitted
to a pipeline whose output is a few paragraphs of prose. Actual conversation is 17%.
Suggested fix: cap per-transcript input size, chunk extraction, or strip
image_generation_* and function_call_output payloads before submission. Any of the
three would have prevented all 11 failures.
2. min_rate_limit_remaining_percent defaults to 25
Per the config reference,
this defaults to 25. In practice that means background generation continues until the
account is down to its last quarter of quota, then logs:
skipping memories startup because Codex rate limits are below the
configured threshold min_remaining_percent=25
This is the only in-product signal about background memory consumption, and it appears
only once quota is nearly gone. It names no subsystem and suggests no remedy.
On a Pro allowance this threshold is unnoticeable. On Plus it means background work can
claim the majority of the weekly budget before the user opens a session. The behaviour is
working as documented — the concern is that the default is not tier-aware and is not
surfaced anywhere in Settings, only in config.toml.
Suggested fix: scale the default to plan tier, and expose the control in
Settings → Personalization alongside the memories toggle.
3. extract_model is unset by default, inheriting the session model
memories.extract_model and memories.consolidation_model are both optional overrides
with no default. With model = "gpt-5.6-luna" set globally, every background
summarization ran on a frontier model.
A user who selects a frontier model for interactive work is silently opting every
background summarization into frontier pricing, with no indication that the two are
coupled.
Suggested fix: default background extraction and consolidation to a small model.
Scale
Across 176 matched jobs on this machine, memory generation ingested 429,400,860 bytes
of transcript. At a rough 4 bytes/token that is on the order of 100M tokens of input,
none of which appears in any local usage accounting — memory_stage1 jobs record no
tokens_used in state_5.sqlite's threads table and write no session rollout.
(Byte-to-token conversion is an estimate and assumes full ingestion without chunking or
truncation. Treat as order-of-magnitude, not a measured token count. The job counts, byte
counts, and error records above are exact.)
Per-day ingestion during the affected period:
| Date |
Bytes |
≈ tokens |
| 2026-07-03 |
40,379,795 |
10,094,948 |
| 2026-07-22 |
29,738,749 |
7,434,687 |
| 2026-07-13 |
23,868,196 |
5,967,049 |
| 2026-07-09 |
21,497,212 |
5,374,303 |
| 2026-07-18 |
14,014,570 |
3,503,642 |
Why this is hard to diagnose
Because the cost scales with transcript size, the pipeline charges more the more the
product is used — and it does so a day later, in a workload that records no token usage,
writes no rollout, and is attributed in usage analytics to an "Exec" bucket that reads
as user-configured non-interactive invocation.
Reproduction
- Enable memories (
[features] memories = true).
- Run several long sessions, ideally including image generation or large tool output.
- Inspect
~/.codex/memories_1.sqlite:
sqlite3 ~/.codex/memories_1.sqlite \
"select status, count(*), substr(last_error,1,60)
from jobs where kind='memory_stage1' group by status;"
- Cross-reference
job_key against the corresponding file size in ~/.codex/sessions/
to see the relationship between transcript size and failure.
Environment: Codex Desktop on macOS, CLI 0.146.0,
[features] memories = trueSummary
Background memory generation (
memory_stage1) submits entire session transcripts to amodel with no size ceiling. On large transcripts this reliably fails with a context-window
error after ingesting the input — consuming quota and producing nothing. Separately, the
shipped defaults allow generation to keep running until only 25% of the plan's quota
remains, and route extraction through whatever model the user selected for interactive
work.
Three distinct problems, in descending order of severity.
1. No per-transcript size cap → repeated context-window failures
memories_1.sqliteon this machine:All 11 failures share the same error, with retries exhausted:
Failed jobs are dramatically larger than successful ones:
Because
retry_remainingreached 0, each of these oversized transcripts was submittedmultiple times, filling a context window and failing on every attempt.
The available settings limit how many rollouts (
max_rollouts_per_startup), howold they may be (
max_rollout_age_days), and how much quota must remain(
min_rate_limit_remaining_percent) — but there is nomax_rollout_bytesequivalent. Asingle oversized transcript is still submitted whole.
Compounding factor: transcripts are mostly non-text payloads. Composition of the
66.8 MB rollout above, all 111 lines of it:
image_generation_endimage_generation_callfunction_call_outputmessage57.4% is base64 image data — seven generated images, embedded twice each — submitted
to a pipeline whose output is a few paragraphs of prose. Actual conversation is 17%.
Suggested fix: cap per-transcript input size, chunk extraction, or strip
image_generation_*andfunction_call_outputpayloads before submission. Any of thethree would have prevented all 11 failures.
2.
min_rate_limit_remaining_percentdefaults to 25Per the config reference,
this defaults to
25. In practice that means background generation continues until theaccount is down to its last quarter of quota, then logs:
This is the only in-product signal about background memory consumption, and it appears
only once quota is nearly gone. It names no subsystem and suggests no remedy.
On a Pro allowance this threshold is unnoticeable. On Plus it means background work can
claim the majority of the weekly budget before the user opens a session. The behaviour is
working as documented — the concern is that the default is not tier-aware and is not
surfaced anywhere in Settings, only in
config.toml.Suggested fix: scale the default to plan tier, and expose the control in
Settings → Personalization alongside the memories toggle.
3.
extract_modelis unset by default, inheriting the session modelmemories.extract_modelandmemories.consolidation_modelare both optional overrideswith no default. With
model = "gpt-5.6-luna"set globally, every backgroundsummarization ran on a frontier model.
A user who selects a frontier model for interactive work is silently opting every
background summarization into frontier pricing, with no indication that the two are
coupled.
Suggested fix: default background extraction and consolidation to a small model.
Scale
Across 176 matched jobs on this machine, memory generation ingested 429,400,860 bytes
of transcript. At a rough 4 bytes/token that is on the order of 100M tokens of input,
none of which appears in any local usage accounting —
memory_stage1jobs record notokens_usedinstate_5.sqlite'sthreadstable and write no session rollout.(Byte-to-token conversion is an estimate and assumes full ingestion without chunking or
truncation. Treat as order-of-magnitude, not a measured token count. The job counts, byte
counts, and error records above are exact.)
Per-day ingestion during the affected period:
Why this is hard to diagnose
Because the cost scales with transcript size, the pipeline charges more the more the
product is used — and it does so a day later, in a workload that records no token usage,
writes no rollout, and is attributed in usage analytics to an "Exec" bucket that reads
as user-configured non-interactive invocation.
Reproduction
[features] memories = true).~/.codex/memories_1.sqlite:job_keyagainst the corresponding file size in~/.codex/sessions/to see the relationship between transcript size and failure.