Bug: Codex TUI overrides terminal cursor style in Neovim :terminal

Open 💬 3 comments Opened May 8, 2026 by xzbdmw

What version of Codex CLI is running?

0.129.0

What subscription do you have?

pro

Which model were you using?

_No response_

What platform is your computer?

_No response_

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

ghostty+neovim 0.12

What issue are you seeing?

Codex emits ESC [ 0 q (DECSCUSR reset to default cursor shape) on every frame when not in Vim insert mode. In embedded terminal emulators like Neovim's built-in
:terminal, this actively overrides the host's configured cursor style (e.g. guicursor), forcing a blinking block cursor instead of the user's configured bar
cursor.

Environment

  • Codex CLI: v0.129.0
  • Neovim: 0.11+ (built-in terminal with "actual cursor" support)
  • OS: macOS (Apple Silicon)
  • Terminal: Neovim :terminal buffer

What steps can reproduce the bug?

Steps to Reproduce

  1. Configure Neovim with a bar cursor for terminal mode:

-- ~/.config/nvim/lua/init.lua
vim.o.guicursor = "n-sm-ve:block-Cursor,t-i-c-ci:ver16-Cursor,r-cr-v-o:hor7-Cursor"

  1. Open Neovim and enter a :terminal buffer.
  2. Confirm the cursor is a vertical bar (as configured by t:ver16-Cursor).
  3. Run codex inside the terminal buffer.
  4. Observe the cursor changes to a blinking block, ignoring the Neovim guicursor setting.

Minimal Reproduction (without Codex)

Inside a Neovim :terminal buffer, run:
printf '\033[0 q'
This sends the same escape sequence Codex emits, and the cursor changes from bar to blinking block — confirming the issue is the ESC [ 0 q escape.

Expected Behavior
When Codex has not intentionally changed the cursor style (i.e., not in Vim insert mode), it should not emit any cursor-shape escape sequence. The host
terminal's cursor configuration should be respected.

Actual Behavior

Codex emits SetCursorStyle::DefaultUserShape (ESC [ 0 q) on every render frame as the default cursor style. In embedded terminals, this is an active reset that
overrides the parent's cursor configuration, not a no-op.

Root Cause

The cursor_style() method in chat_composer.rs (line 4219) returns SetCursorStyle::DefaultUserShape for all non-Vim-insert states:

fn cursor_style(&self, _area: Rect) -> crossterm::cursor::SetCursorStyle {
if self.textarea.uses_vim_insert_cursor() {
crossterm::cursor::SetCursorStyle::SteadyBar
} else {
crossterm::cursor::SetCursorStyle::DefaultUserShape // ← the problem
}
}

This is also the default in renderable.rs (line 20-21) and used in custom_terminal.rs for initialization and reset.

DefaultUserShape is not "do nothing" — it actively sends ESC [ 0 q to the terminal. In standalone terminals this resolves to the user's configured default, but
in embedded terminals (Neovim, tmux with cursor passthrough disabled, etc.) it resolves to "blinking block" which may not match the host's configuration.

What is the expected behavior?

_No response_

Additional information

_No response_

View original on GitHub ↗

This issue has 3 comments on GitHub. Read the full discussion on GitHub ↗