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.md blocks require applies_to: cwd=... in the schema in codex-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 whole memory_summary.md in codex-rs/core/src/memories/prompts.rs:234
- the read prompt injects
{{ memory_summary }} wholesale in codex-rs/core/templates/memories/read_path.md:124
- the full initial context is used when
reference_context_item.is_none() in codex-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 in codex-rs/core/src/memories/phase2.rs:80.
- Confirm that
memory_summary.md now 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.md and 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_summary and MEMORY artifacts 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.md files in the consolidation prompt in codex-rs/core/src/memories/prompts.rs:55, so multiple extensions currently influence one shared memory_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.md a 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
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:197codex-rs/core/templates/memories/consolidation.md:293codex-rs/core/templates/memories/consolidation.md:546However, 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.mdwithout any cwd/project filtering:codex-rs/core/src/codex.rs:3764build_memory_tool_developer_instructions(...)reads the wholememory_summary.mdincodex-rs/core/src/memories/prompts.rs:234{{ memory_summary }}wholesale incodex-rs/core/templates/memories/read_path.md:124reference_context_item.is_none()incodex-rs/core/src/codex.rs:3928Steady-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.mdthat contains both/Users/georgepickett/polyscraperand unrelated/Users/georgepickett/explore-computersections. A freshpolyscrapersession would get both injected, even though only thepolyscrapersection is relevant.This also makes multiple
memories_extensions/*/instructions.mdfiles indirectly compete over one shared global summary: phase 2 reads all extension instructions and rewrites one globalmemory_summary.md, but the runtime still injects that single shared summary into fresh initial context everywhere.Why this matters:
codex-rs/core/src/memories/mod.rs:46, so unrelated repo memory can crowd out the repo that actually mattersWhat steps can reproduce the bug?
codex-rs/core/src/memories/start.rs:14.~/.codex/memories/memory_summary.md. Phase 2's global consolidation pass is incodex-rs/core/src/memories/phase2.rs:80.memory_summary.mdnow contains multiple cwd/project sections./Users/georgepickett/polyscraper).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:
codex-rs/core/src/codex.rs:3764codex-rs/core/src/memories/prompts.rs:234codex-rs/core/templates/memories/read_path.md:124codex-rs/core/src/codex.rs:3928What 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:
memory_summaryandMEMORYartifacts for repo-specific workflow, status, runbooks, and historyMEMORY.md, rollout summaries, skills) scoped to that repo/cwd for later lookupAt 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:
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.instructions.mda mitigation for summary quality, but not a real fix for retrieval/injection scope.Suggested implementation directions:
build_memory_tool_developer_instructions(...)