Windows Codex App 26.409.7971.0 regression: project .codex/config.toml developer_instructions no longer override ~/.codex/config.toml

Open 💬 5 comments Opened Apr 17, 2026 by dawnli
💡 Likely answer: A maintainer (github-actions[bot], contributor) responded on this thread — see the highlighted reply below.

What version of the Codex App are you using (From “About Codex” dialog)?

Windows Store package on this machine:

  • OpenAI.Codex_26.409.7971.0_x64__2p2nqsd0c76g0
  • version: 26.409.7971.0

What subscription do you have?

Not material to the repro.

What platform is your computer?

Microsoft Windows 11 Pro 10.0.26100 x64.

What issue are you seeing?

This appears to be a regression introduced by the Windows desktop update that rolled out on April 16, 2026.

In Codex App on Windows, project-scoped developer_instructions from ./.codex/config.toml no longer override the user-level ~/.codex/config.toml developer_instructions.

This is severe because instruction layering is a core workflow and safety boundary. If repo-local developer_instructions lose precedence, the desktop app can silently apply the wrong developer policy for a repository.

The expected layered behavior is:

  • user-global defaults come from ~/.codex/config.toml
  • project-local overrides come from ./.codex/config.toml
  • for the same key, the project-local value should win in that repository

In the current Windows Codex App build, the effective behavior appears to be the opposite for developer_instructions: the user-level value continues to dominate.

What steps can reproduce the bug?

  1. In ~/.codex/config.toml, set an unmistakable global instruction, for example:
developer_instructions = """
Reply with exactly: GLOBAL
"""
  1. In a trusted project, create ./.codex/config.toml with a conflicting project-local instruction, for example:
developer_instructions = """
Reply with exactly: PROJECT
"""
  1. Confirm the project is trusted.
  2. From that project root, compare behavior between Codex CLI and Codex App.
  3. Start a fresh thread in Codex App for that project.
  4. Ask a trivial prompt that makes the winning instruction obvious.

What is the expected behavior?

For a trusted project, the project-local ./.codex/config.toml developer_instructions should override the user-level ~/.codex/config.toml developer_instructions, matching layered config expectations.

In the example above, the effective instruction in that project should be PROJECT, not GLOBAL.

Actual behavior

On Windows Codex App 26.409.7971.0, the session behaves as if the user-level ~/.codex/config.toml developer_instructions still wins, even in a trusted project with its own ./.codex/config.toml override.

Additional information

This looks related to the broader history of Desktop/App config-layer drift, but it is not the same symptom as older reports.

Related issues:

  • #11004 - Codex App: developer_instructions from config were not attached to app-created threads
  • #13025 - Desktop ignored project .codex/config.toml and only loaded ~/.codex/config.toml for MCP config
  • #17110 - Desktop did not honor project-scoped .codex/config.toml OTel config
  • #14689 - Codex App / CLI config drift around config.toml

Why this one is especially severe:

  • it affects developer_instructions, not just MCP or telemetry config
  • it can invert repository-specific workflow/safety policy
  • it is easy to miss because the app still starts and works, but with the wrong instruction layer winning

Current workarounds are not acceptable as a real fix:

  • duplicating project rules into ~/.codex/config.toml
  • moving the most critical rules into AGENTS.md
  • abandoning the desktop app for CLI in repos that depend on strict project-local instruction overrides

Please treat this as a regression in Desktop/App config precedence on Windows.

View original on GitHub ↗

5 Comments

github-actions[bot] contributor · 4 months ago

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

  • #17110

Powered by Codex Action

etraut-openai contributor · 4 months ago

I'm not able to repro this. I also looked at the code paths that control this behavior, and I don't (or rather, Codex doesn't) see any recent behavioral changes. Can you double check the behavior you're seeing?

sandboxdream · 3 months ago

I can reproduce a closely related/current form of this on Windows App 26.519.5221.0. I also dug through the local packaged app and the Rust app-server sources, and the code path suggests this is not simply project config failing to load. It looks like the Desktop host is injecting a higher-precedence runtime developer_instructions override.

Observed behavior:

  • A project-local ./.codex/config.toml contains top-level developer_instructions.
  • A fresh Codex Desktop thread for that project does not include those instructions in the active developer context.
  • codex debug prompt-input "noop" from the same project root does include the project-local developer_instructions, so the config loader/project config path itself appears to work for CLI.

Source-level chain I found:

  1. The protocol exposes top-level thread instruction fields:
  • codex-rs/app-server-protocol/src/protocol/v2/thread.rs
  • ThreadStartParams { base_instructions: Option<String>, developer_instructions: Option<String>, ... }
  1. The app-server maps the request-level field into ConfigOverrides:
  • codex-rs/app-server/src/request_processors/thread_processor.rs
  • build_thread_config_overrides(..., developer_instructions, ...) -> ConfigOverrides { developer_instructions, ... }
  1. Config merging gives the runtime override precedence over config-file values:
  • codex-rs/core/src/config/mod.rs
  • effectively: developer_instructions.or(cfg.developer_instructions)
  • Therefore, once ConfigOverrides.developer_instructions is Some(...), cfg.developer_instructions from user/project config files is not used.
  1. CLI fresh-thread startup does not set ThreadStartParams.developer_instructions directly. In the TUI/app-server path, fresh thread params are built from the merged Config, but developer_instructions is left as the default None for thread/start:
  • codex-rs/tui/src/app_server_session.rs
  • thread_start_params_from_config(...) -> ThreadStartParams { ..., config: config_request_overrides_from_config(config), ..., ..ThreadStartParams::default() }
  • That lets the app-server load config normally, so project-local developer_instructions can win according to the config-layer rules.
  1. By contrast, the Windows Desktop webview calls a host endpoint before thread/start:
  • packaged app artifact: webview/assets/app-server-manager-signals-*.js
  • it calls fetchFromHost("developer-instructions", { cwd, threadId, threadToolsEnabled, hostId, baseInstructions? })
  1. The Desktop Electron host handler then generates instructions via getProjectAwareDeveloperInstructions(...):
  • packaged app artifact: .vite/build/main-*.js
  • inputs observed there are baseInstructions, cwd, hostId, threadToolsEnabled, threadId, Desktop settings-store Git prefs, conversation detail mode, and workspace-dependencies feature state.
  • I did not see it read project ./.codex/config.toml developer_instructions.
  1. The generated Desktop value is an app-context block assembled by the packaged builder:
  • packaged app artifact: .vite/build/workspace-root-drop-handler-*.js
  • it includes Desktop-specific instructions such as app context, automations, inline code comments, archiving, and Git directive instructions from Desktop settings.

This explains the CLI/Desktop difference:

  • CLI fresh thread: no request-level developer_instructions override, so config-file developer_instructions can be used.
  • Desktop fresh thread: host-generated request-level developerInstructions is sent, app-server treats it as ConfigOverrides.developer_instructions, and the config-file value is short-circuited.

Expected fix direction:

  • Desktop should either avoid setting top-level developerInstructions when it only wants to add app-context instructions, or it should merge the resolved config-layer developer_instructions into the generated Desktop app-context before passing it to thread/start.
  • The important invariant is that project-local .codex/config.toml developer_instructions should not be lost just because Desktop needs to add app-specific instructions.

This may be why the issue is hard to repro by looking only at the Rust config loader: the loader appears to support project-local developer_instructions; the loss happens earlier in the Desktop host/webview path that supplies a higher-precedence override.

sandboxdream · 3 months ago

@etraut-openai I (or rather, Codex) performed a source-level analysis above, and it may explain why this is hard to reproduce when looking only at the Rust config-loader path.

The key distinction appears to be that Desktop fresh thread startup injects a host-generated developerInstructions value. Once it reaches app-server, it becomes a higher-precedence ConfigOverrides.developer_instructions override; CLI/TUI fresh start does not set that top-level field.

When you have time, could you please take another look from the Desktop host/webview startup path? I may still be missing context from the app side, but the evidence above seems to point there rather than to the core config loader.

xavierarrazola · 1 month ago

Still reproducible on Windows with the current Codex Desktop build.

Environment:

  • Windows 11
  • Codex Desktop: 26.707.12708.0
  • Bundled Codex CLI: 0.144.5
  • Config: ~/.codex/config.toml

I added this unmistakable test to the global config:

developer_instructions = """
If the complete user message is exactly:
dev instruction test
reply with exactly:
DEV_INSTRUCTIONS_LOADED
and no other text.
"""

I fully restarted the computer, opened Codex Desktop, created a new task, and sent:

dev instruction test

The main Desktop task ignored the instruction.

Evidence that the config itself is valid and loaded correctly by the underlying runtime:

  1. Python's TOML parser successfully parses the file.
  2. codex debug prompt-input "dev instruction test" includes both the custom instruction marker and DEV_INSTRUCTIONS_LOADED.
  3. Codex Desktop's local title-generation helper also received the instruction and generated DEV_INSTRUCTIONS_LOADED as the task title.
  4. The main Desktop task's session JSONL contains the platform developer message and AGENTS.md content, but the initial context does not contain the configured developer instructions.
  5. The configuration existed before the reboot, so this is not a stale-process or config-reload timing issue.

This isolates the failure to the main Desktop task-creation path: the underlying Codex runtime reads developer_instructions, but the App-created main thread omits or replaces them. The title-generation helper loading them while the main task does not is especially strong evidence of inconsistent instruction construction inside Desktop.

Reproduction task/thread ID:
019f6c9a-b54f-7793-a21a-e1302b77d395