ChatGPT desktop app: Codex shell tool output mishandles carriage returns with ANSI sequences (ESC[K and SGR 8)

Open 💬 0 comments Opened Jul 16, 2026 by progbeat

What version of the Codex App are you using?

26.707.91948 (build 5440)

What subscription do you have?

Pro

What platform is your computer?

Darwin 25.3.0 arm64 arm

What issue are you seeing?

When the model runs a script through the shell tool in a Codex task, the tool output displayed in the ChatGPT desktop app does not preserve terminal semantics when a carriage return is combined with ANSI control sequences.

This concerns output from a shell command invoked by the model. It is not a command entered manually in the app's built-in terminal.

Two operations produce behavior opposite to a normal terminal:

  • \rHello\x1b[K does not erase the rest of the line. Some of the previous characters remain after Hello.
  • \rHello\x1b[8m hides characters that were already present on the line, even though SGR 8 should only affect subsequently printed characters.

What steps can reproduce the bug?

Create a file named compare_line_clear.py in a workspace:

#!/usr/bin/env python3

import time

CONCEAL = "\x1b[8m"
REVEAL = "\x1b[28m"


def print_dashes():
    for _ in range(20):
        print("-", end="", flush=True)
        time.sleep(0.25)
    time.sleep(2)


print("1. Erase using ESC[K")
print_dashes()
print("\rHello\x1b[K")

time.sleep(2)

print("2. Hide using CONCEAL")
print_dashes()
print(f"\rHello{CONCEAL}", end=f"\n{REVEAL}", flush=True)

Then:

  1. Open the workspace in the ChatGPT desktop app and start a Codex task.
  2. Ask the model: Run python3 compare_line_clear.py.
  3. Let the model invoke its shell tool.

The shell tool output displayed in the conversation is:

1. Erase using ESC[K
Hello-----------
2. Hide using CONCEAL
Hello
  1. Open a regular terminal in the same workspace and manually run:
python3 compare_line_clear.py

The regular terminal displays:

1. Erase using ESC[K
Hello
2. Hide using CONCEAL
Hello---------------

The bug does not require using the app's built-in interactive terminal. It is specifically reproducible in the conversation output produced when the model invokes the shell tool.

What is the expected behavior?

The shell tool output shown in the Codex conversation should reproduce standard terminal behavior:

  • CSI K (ESC[K) should erase from the cursor to the end of the current line.
  • SGR 8 (CONCEAL) should affect only text printed after the sequence. It should not retroactively hide cells that were already displayed.

If the conversation output renderer intentionally does not emulate all terminal control sequences, unsupported sequences should at least not affect carriage-return column calculations or retroactively change the styling of retained text.

Additional information

This appears to be a ChatGPT desktop app Codex conversation-output rendering issue rather than a PTY, Python, or shell issue. The same process output renders correctly when the script is started manually in a regular terminal.

Inspection of the bundled frontend indicates that carriage-return output is textually reconstructed before ANSI parsing using logic equivalent to:

replacement + previousText.slice(replacement.length)

The raw ANSI escape bytes are therefore counted as display columns:

  • With ESC[K, the control sequence increases replacement.length, but erase-in-line is not emulated, leaving an incorrect suffix.
  • With SGR 8, part of the previous suffix is reconstructed after the conceal sequence and then parsed as hidden text, causing previously visible cells to disappear retroactively.

A renderer based on terminal cells/columns, or preprocessing that excludes zero-width control sequences from column calculations and implements CSI K, would avoid the inconsistency.

View original on GitHub ↗