Default goal continuation can preserve stale Plan Mode instructions when developer_instructions is null

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

Summary

I hit a /goal-adjacent variant of the stale Plan Mode issue where the recorded/logical collaboration mode was Default, but the assistant continued to behave as if Plan Mode was still active.

This looks related to #18954 / #10185, but this report adds a narrower root-cause hypothesis and a minimal core-level characterization test.

Observed behavior

In a local Codex session:

  • A goal was active.
  • Several turns were recorded as Default mode:
  • collaboration_mode_kind = "default"
  • collaboration_mode.mode = "default"
  • However, those same turns had:
  • collaboration_mode.settings.developer_instructions = null
  • During those Default/null turns, the assistant repeatedly emitted <proposed_plan> and said it could not edit/create files because it was still in Plan Mode.
  • A later Default turn included the Default collaboration developer instructions again:
  • # Collaboration Mode: Default
  • “Any previous instructions for other modes ... are no longer active.”
  • Immediately after that reset instruction reappeared, the assistant resumed implementation behavior.

So the symptom was not simply “the user is still in Plan Mode.” The recorded mode was Default, but the model-visible instruction state still appeared to contain stale Plan Mode constraints.

Current main checked

I checked current main at:

cf0911076f234e0219bd8d61dd3bc2f80a2df287

Current app-server turn/start appears to mitigate this for normal v2 turn requests:

  • codex-rs/app-server/src/request_processors/turn_processor.rs
  • TurnProcessor::normalize_collaboration_mode(...)
  • If developer_instructions is missing, it fills from builtin_collaboration_mode_presets().

That means the normal app-server request path may already be safer now.

However, the core context update path still has the failure mode if a Default collaboration mode with missing instructions reaches core.

Suspected root cause

In codex-rs/core/src/context_manager/updates.rs, build_collaboration_mode_update_item(previous, next) detects a collaboration mode change, but then does:

CollaborationModeInstructions::from_collaboration_mode(&next.collaboration_mode)?

In codex-rs/core/src/context/collaboration_mode_instructions.rs, from_collaboration_mode returns None when settings.developer_instructions is None or empty.

The consequence is already described by the source comment in updates.rs:

// If the next mode has empty developer instructions, this returns None and we emit no
// update, so prior collaboration instructions remain in the prompt history.

That matches the observed rollout shape: logical Default mode, but no Default reset developer message, so earlier Plan Mode instructions can remain model-visible.

Goal-mode relevance

This may be triggered or made visible by goal continuation:

  • codex-rs/core/src/goals.rs
  • maybe_start_goal_continuation_turn starts a continuation with new_default_turn_with_sub_id(...).
  • should_ignore_goal_for_mode returns true only for ModeKind::Plan, so Default-mode goal continuation is allowed.

This supports the hypothesis that /goal itself is not forcing Plan Mode. Instead, a goal continuation/resume/internal turn can be logically Default while still missing the Default collaboration reset instructions.

Minimal characterization test

I added this local characterization test against codex-core:

#[tokio::test]
async fn build_settings_update_items_omits_collaboration_reset_for_default_without_instructions() {
    // previous: Plan mode with developer instructions
    // next: Default mode with developer_instructions: None
    // observed: no developer collaboration reset/update is emitted
}

Command:

cargo test -p codex-core build_settings_update_items_omits_collaboration_reset_for_default_without_instructions

Result:

running 1 test
test session::tests::build_settings_update_items_omits_collaboration_reset_for_default_without_instructions ... ok

test result: ok. 1 passed

The characterization confirms current core behavior: Plan -> Default plus missing Default developer_instructions emits no <collaboration_mode> reset/update.

Expected behavior

When the collaboration mode changes from Plan to Default, the model should receive an authoritative Default-mode reset instruction, even if the next CollaborationMode object has developer_instructions = None.

Otherwise, a turn can be logically Default while the prompt history still contains effective Plan Mode constraints.

Possible fix directions

Some possible approaches:

  • Normalize Default collaboration mode earlier/centrally so built-in Default developer instructions are always present before core context diffing.
  • Or make build_collaboration_mode_update_item emit an explicit Default reset message when mode changes to Default and next instructions are missing.
  • Avoid duplicate emission when the normal Default instructions are already present.

Related issues

  • #18954: Intermittent mismatch between displayed collaboration mode and actual model mode
  • #10185: Mode switch Plan -> Code still behaves like Plan
  • #21512: /goal command will edit files directly with plan mode on
  • #20656: Plan mode makes active /goal look stuck because continuation is suppressed silently

cc @etraut-openai because this may be a narrower root-cause variant of the /goal + Plan Mode behavior discussed in #21512 / #20656.

View original on GitHub ↗

2 Comments

github-actions[bot] contributor · 2 months ago

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

  • #24331

Powered by Codex Action

Northern-Summer · 1 month ago

I can confirm this still affects the Windows Codex App path, and I also validated a small core-side fix locally.

Desktop evidence from my machine:

  • Codex App package version: 26.623.9142.0
  • Windows: Microsoft Windows NT 10.0.26200.0 x64
  • Local app-server startup log:
2026-06-30T03:32:33.390Z info [AppServerConnection] Starting app-server connection hostId=local transport=stdio
2026-06-30T03:32:36.688Z info [StdioConnection] stdio_transport_spawned ... executablePath="C:\\Program Files\\WindowsApps\\OpenAI.Codex_26.623.9142.0_x64__2p2nqsd0c76g0\\app\\resources\\codex.exe"
2026-06-30T03:32:38.147Z info [AppServerConnection] Current reported app-server version: currentVersion=0.142.4 hostId=local

So the packaged desktop app is still driving the bundled local app-server over stdio.

I patched current local source in:

  • codex-rs/core/src/context/collaboration_mode_instructions.rs
  • codex-rs/core/src/context_manager/updates.rs
  • codex-rs/core/tests/suite/collaboration_instructions.rs

Patch behavior:

  • if collaboration mode changes to Default and incoming developer_instructions is None, resolve the builtin Default collaboration instructions instead of returning None
  • this ensures Plan -> Default emits an actual reset update instead of silently leaving stale Plan instructions in history

Local verification passed:

cargo test -p codex-core resolves_builtin_default_instructions_when_mode_uses_null_override --lib
cargo test -p codex-core collaboration_mode_update_uses_builtin_default_instructions_when_reset_is_null --test all

One more practical note for Windows triage: replacing AppData\\Local\\OpenAI\\Codex\\bin\\...\\codex.exe does not affect the desktop main app-server path. The desktop host continues to spawn the packaged WindowsApps\\...\\resources\\codex.exe. So this is easy to validate in source, but awkward to validate end-to-end in the installed Windows app without a supported remote-host/dev override path.