Deduplicate AGENTS.md when CODEX_HOME is also the project root

Open 💬 2 comments Opened Jul 19, 2026 by grig2277

Summary

When CODEX_HOME is also the project root and current working directory, Codex loads the same canonical AGENTS.md file twice:

  1. as the global $CODEX_HOME/AGENTS.md;
  2. again through project instruction discovery.

The second copy is wrapped as --- project-doc ---.

Environment

  • codex-cli 0.144.6
  • Linux x86_64
  • zsh

Minimal reproduction

tmp="$(mktemp -d)"
export CODEX_HOME="$tmp"
cd "$tmp"
git init -q
printf '# CANONICAL_DEDUPE_MARKER\n' > AGENTS.md

codex debug prompt-input DEDUPE_CHECK |
  jq -c '[.. | strings] as $strings |
    {marker_count:([$strings[] | scan("# CANONICAL_DEDUPE_MARKER")]|length),
     project_doc_wrappers:([$strings[] | scan("--- project-doc ---")]|length)}'

Observed: the marker appears twice and one project-doc wrapper is present.

The same behavior was measured in a real Codex home repository:

{"agents_headers":2,"project_doc_wrappers":1,"marker_count":1,"total_string_bytes":45422}

With the one-run override -c project_doc_max_bytes=0:

{"agents_headers":1,"project_doc_wrappers":0,"marker_count":1,"total_string_bytes":31123}

Expected behavior

Instruction assembly should deduplicate identical canonical source paths across global and project discovery. If $CODEX_HOME/AGENTS.md was already loaded globally, project discovery should not append the same file again.

Impact

  • duplicate durable instructions in every turn;
  • unnecessary input-token consumption;
  • additional prompt processing latency;
  • misleading provenance because one physical file appears as two logical instruction layers.

Configuration limitations

  • Named profiles require explicit --profile selection.
  • Project config cannot select a profile.
  • A global project_doc_max_bytes=0 would incorrectly disable project instructions in every repository.
  • A conditional -c project_doc_max_bytes=0 suppresses the duplicate locally, but also suppresses the entire project instruction chain and is only a workaround.

Related work

  • #23416 tracks incorrect instruction provenance when both global and project instructions are loaded.
  • #17091 reports global and project AGENTS.md as separate layers in /status, but does not deduplicate identical paths.

View original on GitHub ↗

2 Comments

Kevinjohn · 1 month ago

The same AGENTS.md is currently injected twice when CODEX_HOME is also the local project root.

Confirmed against current main at 678157acaa.

  • Observable sequence: load $CODEX_HOME/AGENTS.md as global instructions, then run project instruction discovery from that same directory.
  • Expected: the physical source appears once as global instructions.
  • Actual: the same source is appended again as a project entry and rendered behind a --- project-doc --- separator.

The prepared patch is limited to instruction assembly:

  • convert the global instruction source to its PathUri once;
  • when merging locally discovered project entries, discard only an entry with that exact source path;
  • leave remote-environment entries untouched, since a matching path string there may identify a different physical file;
  • add a regression test comparing the complete assembled LoadedAgentsMd object and requiring an empty project-entry list.

Actual screenshots

Before — the focused regression exposes the duplicate project entry

!Before: VS Code terminal shows the focused AGENTS.md regression failing because the assembled instructions contain a duplicate Project entry

After — the same focused regression passes

!After: VS Code terminal shows the same focused AGENTS.md deduplication regression passing

Validation:

  • agents_md::tests: 42/42 passed
  • just fix -p codex-core: passed
  • just fmt: passed

---

I have a PR ready if issue accepted

PaulRBerg · 26 days ago

Still reproducible on codex-cli 0.146.0 via codex debug prompt-input. This is especially annoying when $CODEX_HOME is itself version-controlled: opening the settings/config repo is a normal workflow, but every turn duplicates the global AGENTS.md and burns context unless the user remembers a bespoke profile or one-off override.