/goal command will edit files directly with plan mode on

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

What version of Codex CLI is running?

codex-cli 0.128.0

What subscription do you have?

plus

Which model were you using?

gpt-5.5

What platform is your computer?

Microsoft Windows NT 10.0.26200.0 x64

What terminal emulator and version are you using (if applicable)?

Windows Terminal PowerShell

What issue are you seeing?

when I let codex to make a develop plan of some features with /goal command and plan mode on, codex not give me the final plan but edit files directly maybe following its plan

What steps can reproduce the bug?

⚠ Under-development features enabled: goals. Under-development features are incomplete and may behave unpredictably.
  To suppress this warning, set `suppress_unstable_features_warning = true` in C:\Users\54083\.codex\config.toml.

• Model changed to gpt-5.5 xhigh

• Model changed to gpt-5.5 medium for Plan mode.

• Model changed to gpt-5.5 xhigh for Default mode.

• Model changed to gpt-5.5 medium for Plan mode.

• Goal active Objective: The current coder may encounter non-fatal issues such as high cyclomatic complexity when generating code. Provide solutions for potential similar issues.
• I will now start modifying the file: ReviewerAgent will add a new output of quality_recommendations and include medium/low/info coder-owned advisories 
 Enter feedback_for_coder; the coder prompt will add a new section with explicit complexity and nesting control requirements.

What is the expected behavior?

Plan mode should have higher priority than other features, which means when plan mode is on, even /goal command should not edit files directly.

Additional information

_No response_

View original on GitHub ↗

7 Comments

github-actions[bot] contributor · 2 months ago

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

  • #20656

Powered by Codex Action

CeitherNSW · 2 months ago
Potential duplicates detected. Please review them and close your issue if it is a duplicate. * Plan mode makes active /goal look stuck because continuation is suppressed silently #20656 _Powered by Codex Action_

not a duplicated issue

longsizhuo · 2 months ago

Maybe it is a "bypass mode" in other words lol

etraut-openai contributor · 2 months ago

Thanks for reporting. Yes, there are known issues with goal mode and plan mode. They aren't intended to be used together. The intended design is for the goal to be suspended until after you exit plan mode. I'll work on a fix.

etraut-openai contributor · 2 months ago

@CeitherNSW, I'm not able to repro this with the latest version (0.130.0). Perhaps I'm missing a critical step. Can you provide steps you used to repro the problem?

MakotoUwu · 2 months ago

I found a related repro on codex-cli 0.130.0 that may explain why this feels broken from the user side.

This looks less like "Plan mode edits files" and more like: once a goal is active, goal continuation can start a default-mode turn before a client/user can successfully enter Plan mode. A subsequent Plan request then appears to be incorporated into the active goal turn, not started as a real Plan-mode turn.

Environment

  • Codex CLI: codex-cli 0.130.0
  • App-server path: codex app-server --listen stdio:// --enable goals
  • Feature flag: goals = true
  • Local client used thread/start, thread/goal/set, then turn/start

Repro shape

  1. Start a fresh materialized thread with thread/start.
  2. Set an active goal with thread/goal/set:

``text
Plan a tiny README section for a fictional local tool named GoalPlanProbe.
The plan should mention GoalPlanProbe exactly once.
Do not edit files during planning.
``

  1. Immediately send a turn/start request that asks for Plan mode:

``json
{
"collaborationMode": {
"mode": "plan",
"settings": {
"model": "gpt-5.4-mini",
"reasoning_effort": "low",
"developer_instructions": null
}
},
"input": [
{
"type": "text",
"text": "Make a plan for the current active goal. I am intentionally not restating the goal text in this message. Do not run commands or edit files."
}
]
}
``

Observed behavior

The persisted rollout for the resulting turn shows:

"collaboration_mode": {
  "mode": "default",
  "settings": {
    "model": "gpt-5.5",
    "reasoning_effort": "xhigh",
    "developer_instructions": null
  }
}

The same turn also contains the goal-continuation developer message:

Continue working toward the active thread goal.

The user message asking for a plan is included in that default-mode goal turn. The assistant then produced a <proposed_plan>-looking answer, called update_goal, and the goal changed from active to complete.

Final assistant text included:

<proposed_plan>
...
</proposed_plan>

Goal marked complete. Usage: 0 of 50000 tokens, 17 seconds.

Why I think this is confusing

In #20656, @etraut-openai said:

Goal mode is intentionally suppressed while you're in plan mode.

That policy makes sense. But from the client/user perspective, the current behavior can still feel like Plan mode is broken around an active goal:

  • the user tries to plan while a goal is active;
  • the active goal turn remains in default mode;
  • the planning request is handled as part of goal execution;
  • the goal can be completed even though the user was trying to plan first.

Expected behavior / question

Is this the intended app-server/client contract?

If an active goal turn is already running and the client asks for Plan mode, I would expect one of these clearer outcomes:

  • reject the Plan-mode request with a clear "cannot switch mode while a goal turn is running" error;
  • queue it until the goal turn is done;
  • pause/suspend the goal before starting a real Plan-mode turn;
  • or expose an explicit "Plan from goal" path that treats the active goal as read-only planning context and does not run goal continuation.

At minimum, it would help if the UI/protocol made clear that the user is still in default goal execution, not Plan mode.

CeitherNSW · 2 months ago
@CeitherNSW, I'm not able to repro this with the latest version (0.130.0). Perhaps I'm missing a critical step. Can you provide steps you used to repro the problem?

@etraut-openai I just reproed it in ``0.132`` the newest version I think. And the method is still:

  • switch to plan mode
  • type ``/goal`` and my prompt
  • and it just modified the files

also , I will provide the output of the whole process

│                                             │
│ model:     gpt-5.5 xhigh   /model to change │
│ directory: ~\Desktop\archive\codex-repro    │
╰─────────────────────────────────────────────╯

  Tip: GPT-5.5 is now available in Codex. It's our strongest agentic coding model yet, built to reason through large
  codebases, check assumptions with tools, and keep going until the work is done.

  Learn more: https://openai.com/index/introducing-gpt-5-5/

• Model changed to gpt-5.5 medium for Plan mode.

• Goal active Objective: create hello_world.x source files in different major coding language

• SessionStart hook (failed)
⚠ Falling back from WebSockets to HTTPS transport. timeout waiting for child process to exit

• I’ll inspect the workspace first so I don’t duplicate or overwrite any existing hello_world.* files, then I’ll add the
  missing source files and verify them.

• Running git status --short

• Ran git status --short
  └ fatal: not a git repository (or any of the parent directories): .git

• Ran rg --files
  └ C:\Users\54083\Documents\WindowsPowerShell\Microsoft.PowerShell_profile.ps1 : 无法使用点 '.' 获得此命令来源,因为该
    命令
    … +12 lines (ctrl + t to view transcript)
        + FullyQualifiedErrorId : PropertySetterNotSupportedInConstrainedLanguage


────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────

• The workspace is not a Git repo, and PowerShell’s profile is interfering with normal command startup. I’m switching to
  non-login shell calls for the filesystem checks.

• Running Get-Location

• Running Get-ChildItem -Recurse -File -Filter 'hello_world*'

• Ran Get-Location
  └
    Path
    … +2 lines (ctrl + t to view transcript)



• Ran Get-ChildItem -Force
  └ (no output)

• Ran Get-ChildItem -Recurse -File -Filter 'hello_world*'
  └ (no output)

• Updated Plan
  └ The workspace is empty and not a Git repository, so I’ll add standalone source files at the workspace root.
    ✔ Inspect workspace for existing files
    □ Create hello_world source files across major languages
    □ Verify files exist and contain runnable Hello World examples

────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────

• I’m going to add standalone hello_world.<ext> files at the workspace root, each using the normal entry point or idiom
  for that language while keeping the filename pattern consistent.

• Edited 17 files (+57 -0)
  └ hello_world.c (+6 -0)
    1 +#include <stdio.h>
    2 +
    3 +int main(void) {
    4 +    puts("Hello, World!");
    5 +    return 0;
    6 +}

  └ hello_world.cpp (+6 -0)
    1 +#include <iostream>
    2 +
    3 +int main() {
    4 +    std::cout << "Hello, World!" << std::endl;
    5 +    return 0;
    6 +}

  └ hello_world.cs (+9 -0)
    1 +using System;
    2 +
    3 +class Program
    4 +{
    5 +    static void Main()
    6 +    {
    7 +        Console.WriteLine("Hello, World!");
    8 +    }
    9 +}

  └ hello_world.go (+7 -0)
    1 +package main
    2 +
    3 +import "fmt"
    4 +
    5 +func main() {
    6 + fmt.Println("Hello, World!")
    7 +}

  └ hello_world.java (+5 -0)
    1 +class hello_world {
    2 +    public static void main(String[] args) {
    3 +        System.out.println("Hello, World!");
    4 +    }
    5 +}

  └ hello_world.js (+1 -0)
    1 +console.log("Hello, World!");

  └ hello_world.kt (+3 -0)
    1 +fun main() {
    2 +    println("Hello, World!")
    3 +}

  └ hello_world.lua (+1 -0)
    1 +print("Hello, World!")

  └ hello_world.php (+3 -0)
    1 +<?php
    2 +
    3 +echo "Hello, World!" . PHP_EOL;

  └ hello_world.py (+1 -0)
    1 +print("Hello, World!")

  └ hello_world.r (+1 -0)
    1 +cat("Hello, World!\n")

  └ hello_world.rb (+1 -0)
    1 +puts "Hello, World!"

  └ hello_world.rs (+3 -0)
    1 +fn main() {
    2 +    println!("Hello, World!");
    3 +}
    1 +object hello_world {
    2 +  def main(args: Array[String]): Unit = {
    3 +    println("Hello, World!")
    4 +  }
    5 +}

  └ hello_world.sh (+3 -0)
    1 +#!/usr/bin/env sh
    2 +
    3 +printf '%s\n' 'Hello, World!'

  └ hello_world.swift (+1 -0)
    1 +print("Hello, World!")

  └ hello_world.ts (+1 -0)
    1 +console.log("Hello, World!");

────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────

• The files are in place. I’m checking the final file set and confirming each source contains the expected Hello World
  output.

• Running Get-ChildItem -File -Name hello_world.*

• Ran Get-ChildItem -File -Name hello_world.*
  └ hello_world.c
    hello_world.swift
    hello_world.ts

• Ran Select-String -Path hello_world.* -Pattern 'Hello, World!'
  └
    hello_world.c:4:    puts("Hello, World!");
    … +16 lines (ctrl + t to view transcript)



• Updated Plan
  └ ✔ Inspect workspace for existing files
    ✔ Create hello_world source files across major languages
    ✔ Verify files exist and contain runnable Hello World examples

────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────

• Created 17 hello_world.* source files in the workspace:

  c, cpp, cs, go, java, js, kt, lua, php, py, r, rb, rs, scala, sh, swift, and ts.

  Verified that all files exist and each contains a Hello, World! output statement. Goal marked complete. Usage: 37,934
  tokens, about 3m 46s elapsed.

• Stop hook (failed)
  error: hook exited with code 1

─ Worked for 4m 13s ────────────────────────────────────────────────────────────────────────────────────────────────────


› Write tests for @filename

  gpt-5.5 medium · ~\Desktop\archive\codex-repro                                        Plan mode (shift+tab to cycle)