Memory read path ignores cwd and injects entire global memory_summary.md into initial context for new sessions
What issue are you seeing?
Codex's memory write path is cwd-aware, but the memory read/injection path is not.
Today, phase 2 consolidation explicitly preserves cwd/project boundaries in the memory artifacts:
MEMORY.mdblocks requireapplies_to: cwd=...in the schema incodex-rs/core/templates/memories/consolidation.md:197- the consolidation instructions say to separate similar tasks across different cwd contexts by default in
codex-rs/core/templates/memories/consolidation.md:293 - the summary/index is organized first by cwd/project scope in
codex-rs/core/templates/memories/consolidation.md:546
However, when Codex builds the initial context for a fresh conversation / baseline, the runtime prompt injection path reads and injects the entire global ~/.codex/memories/memory_summary.md without any cwd/project filtering:
- the initial context builder appends the memory developer prompt in
codex-rs/core/src/codex.rs:3764 build_memory_tool_developer_instructions(...)reads the wholememory_summary.mdincodex-rs/core/src/memories/prompts.rs:234- the read prompt injects
{{ memory_summary }}wholesale incodex-rs/core/templates/memories/read_path.md:124 - the full initial context is used when
reference_context_item.is_none()incodex-rs/core/src/codex.rs:3928
Steady-state turns appear to use the settings-diff path instead of rebuilding the full initial context, so this is specifically an initial-context / new-conversation boundary issue rather than a claim that the full memory summary is re-injected on every turn.
This still creates a real failure mode for multi-repo users: a fresh session in one repo gets irrelevant memory from other repos injected into context before the model starts working. That is both noisy and architecturally inconsistent with the cwd-aware write/consolidation design.
Concretely, I have a generated memory_summary.md that contains both /Users/georgepickett/polyscraper and unrelated /Users/georgepickett/explore-computer sections. A fresh polyscraper session would get both injected, even though only the polyscraper section is relevant.
This also makes multiple memories_extensions/*/instructions.md files indirectly compete over one shared global summary: phase 2 reads all extension instructions and rewrites one global memory_summary.md, but the runtime still injects that single shared summary into fresh initial context everywhere.
Why this matters:
- irrelevant context can bias the model toward the wrong workflow
- unrelated memory competes for the limited injected summary budget
- the injected summary is truncated to 5,000 tokens in
codex-rs/core/src/memories/mod.rs:46, so unrelated repo memory can crowd out the repo that actually matters - the system is storing project boundaries in the data model but not respecting them in retrieval/injection
What steps can reproduce the bug?
- Enable memories and allow the startup memory pipeline to run. The startup trigger is in
codex-rs/core/src/memories/start.rs:14. - Use Codex across at least two distinct repos/cwds so phase 1 and phase 2 build cross-project memory.
- Let phase 2 consolidate those memories into a shared
~/.codex/memories/memory_summary.md. Phase 2's global consolidation pass is incodex-rs/core/src/memories/phase2.rs:80. - Confirm that
memory_summary.mdnow contains multiple cwd/project sections. - Start a new top-level session in one repo (for example,
/Users/georgepickett/polyscraper). - Observe from the code path that the initial context builder reads the entire
memory_summary.mdand injects it without filtering to the current cwd/project.
This is easiest to see from the code rather than a single UI screenshot:
- injection gate:
codex-rs/core/src/codex.rs:3764 - full-file read:
codex-rs/core/src/memories/prompts.rs:234 - prompt template includes the whole summary:
codex-rs/core/templates/memories/read_path.md:124 - fresh baseline path:
codex-rs/core/src/codex.rs:3928
What is the expected behavior?
The read path should respect the same repo/cwd boundary that the write/consolidation path is already trying to preserve.
A better architecture would be a hybrid model:
- maintain a tiny global user profile for genuinely cross-project preferences
- maintain per-repo/per-cwd
memory_summaryandMEMORYartifacts for repo-specific workflow, status, runbooks, and history - on a new session / fresh baseline, inject:
- the tiny global profile, plus
- only the matching repo/cwd summary for the current session
- keep repo-specific detailed memory (
MEMORY.md, rollout summaries, skills) scoped to that repo/cwd for later lookup
At minimum, build_memory_tool_developer_instructions(...) should filter or select the relevant section(s) of the summary by current cwd/project before injection, instead of pasting the entire global file.
Additional information
A few related design tensions surfaced while tracing this locally:
- Phase 2 reads all
memories_extensions/*/instructions.mdfiles in the consolidation prompt incodex-rs/core/src/memories/prompts.rs:55, so multiple extensions currently influence one sharedmemory_summary.md. - Because the runtime injects one global summary into fresh initial context, those extensions indirectly compete for a single prompt budget over time.
- This makes
instructions.mda mitigation for summary quality, but not a real fix for retrieval/injection scope.
Suggested implementation directions:
- add cwd/project-aware selection inside
build_memory_tool_developer_instructions(...) - or split artifacts into:
- global profile summary
- per-repo/per-cwd summary
- per-repo/per-cwd detailed memory
- use current cwd/project root as the primary routing key, with global profile as a fallback/overlay
This issue has 3 comments on GitHub. Read the full discussion on GitHub ↗