Skip to content

Memory read path ignores cwd and injects entire global memory_summary.md into initial context for new sessions #17496

Closed

Description

@grp06

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?

  1. Enable memories and allow the startup memory pipeline to run. The startup trigger is in codex-rs/core/src/memories/start.rs:14.
  2. Use Codex across at least two distinct repos/cwds so phase 1 and phase 2 build cross-project memory.
  3. 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.
  4. Confirm that memory_summary.md now contains multiple cwd/project sections.
  5. Start a new top-level session in one repo (for example, /Users/georgepickett/polyscraper).
  6. 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

Activity

  1. added
    bugSomething isn't working
    CLIIssues related to the Codex CLI
    sessionIssues involving session (thread) management, resuming, forking, naming, archiving
    contextIssues related to context management (including compaction)
    on Apr 11, 2026
  2. changed the title [-]Memory injection ignores repo/cwd boundaries and injects unrelated global summary into new sessions[/-] [+]Memory read path ignores cwd and injects entire global memory_summary.md into new sessions[/+] on Apr 11, 2026
  3. github-actions commented on Apr 11, 2026

    @github-actions
    Contributor

    Potential duplicates detected. Please review them and close your issue if it is a duplicate.

    Powered by Codex Action

  4. added
    agentIssues related to the core agent loop
    and removed
    CLIIssues related to the Codex CLI
    contextIssues related to context management (including compaction)
    sessionIssues involving session (thread) management, resuming, forking, naming, archiving
    on Apr 11, 2026
  5. changed the title [-]Memory read path ignores cwd and injects entire global memory_summary.md into new sessions[/-] [+]Memory read path ignores cwd and injects entire global memory_summary.md into initial context for new sessions[/+] on Apr 11, 2026
  6. raye-deng commented on Apr 12, 2026

    @raye-deng

    This is a sharp observation — the asymmetry between write-path and read-path cwd awareness is exactly the kind of inconsistency that causes subtle, hard-to-reproduce failures in agent workflows.

    The practical impact is worse than "wrong context gets loaded." When global memory from project A gets injected into a session for project B, the agent may:

    1. Import packages that exist in project A but not project B — the agent "knows" about project-a-utils from memory and generates an import. Compiles fine if types are cached. Fails at runtime with MODULE_NOT_FOUND.

    2. Apply architecture patterns from one project to another — project A uses hexagonal architecture with dependency injection, project B is a simple Express CRUD. The agent generates DI containers and interface abstractions for project B because global memory tells it "this team uses hexagonal architecture." Code review approves because it looks clean. But now a simple feature takes 7 files instead of 2.

    3. Generate API calls to wrong endpoints — memory contains "API base is /api/v2" from project A, but project B uses /api/v1. The agent generates correct-looking fetch calls that hit 404s or, worse, silently hit the wrong data.

    The reason this is hard to catch: none of these failures look like bugs in isolation. Each one looks like "the developer made a reasonable choice that happened to be wrong for this specific project." Traditional linters and SonarQube can't distinguish between a correct import and a correct-looking-but-contextually-wrong import.

    The cwd-aware read path fix you're proposing is the right approach. On our side, we handle this by validating imports and API references against the actual project context (not global state) as part of the PR pipeline. npx @opencodereview/cli scan . --sla L1 if you want to see what context-aware import validation looks like in practice.

  7. jif-oai commented on Apr 13, 2026

    @jif-oai
    Contributor

    This is by design for the current models

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    agentIssues related to the core agent loopbugSomething isn't working

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions