Customizing Codex's interface should increase observability, not turn the TUI into decoration. The difference is fundamental: the status line and title are needed not for beauty but to see at any moment the conditions the work runs in. The most useful fields are predictable: the model and reasoning, the remaining context, the Git branch, the current directory, the limits and the session id. All of this answers the question "where am I and what is in play now" without a separate command.
The interface is configured both by commands and by config. It helps to see them side by side once. The /statusline, /title, /keymap, /theme and /personality commands manage the corresponding aspects interactively, while the [tui] section in config sets the same declaratively and permanently. Below is a [tui] fragment with a status line of useful fields, the terminal title, the vim mode and raw output. The declarative setup outlives the session, the interactive one is handy for a quick try.
The status line is assembled from fields that really help make decisions. model-with-reasoning shows which model and depth are in play; context-remaining warns about the context filling before it starts to be lost; git-branch and current-dir confirm where exactly you are working. These are not decorations but signals: noticing that the context is running out or the branch is wrong is cheaper by the status line than discovering it after the fact from a strange result.
The terminal title and keymap are about convenience and predictability, not style. A terminal_title of the project, branch and status helps not to confuse windows when there are several. Keymap and vim_mode_default adjust input to habit, but with the same caveat as everywhere: combinations may be intercepted by the terminal or IDE, so remaps are introduced one at a time and checked rather than rewriting everything at once. Raw output is disabled or enabled for a specific task, understanding the effect.
IDE settings live on their own boundary, and it matters to understand it. They manage the editor integration and presentation, but the core - the model, sandbox, approvals and MCP - is taken from the shared config layers, not from the editor settings. The practical consequence: the source of truth for policy is config.toml, reached in the IDE via gear, Codex Settings, Open config.toml. Duplicating policy in editor-specific settings without need is not worth it - it breeds two places easy to desync.
Hence a rule for mixed environments: keep policy in the shared config rather than smearing it across editors. If each client sets its own permissions and sandbox in its own way, behavior becomes unpredictable and depends on where you opened the project. A single source in config.toml makes behavior portable between the CLI, IDE and desktop. Editor-specific settings are left for what is truly specific to the editor - presentation and integration - not for security boundaries.
Separately there is the choice of execution target and review surface - it is made consciously. The same prompt on Local, in a Worktree and in the Cloud has different inputs, different secrets and a different recovery path. Local sees your machine, a Worktree isolates, the Cloud works with a fresh clone without your local files. Customizing the status line is exactly what helps not to confuse them: seeing the current execution target is part of the same observability everything is configured for.
The typical failures around customization are predictable. Configuring the TUI for looks rather than observability and not putting useful fields into the status. Rewriting the keymap entirely and getting combinations intercepted by the terminal. Setting policy in editor-specific settings instead of the shared config and desyncing behavior. And not noticing the execution target, running one prompt in different environments with different consequences. Configure the interface for signals, keep policy in config, and choose the execution target consciously.
[tui]
status_line = ["model-with-reasoning", "context-remaining", "git-branch", "current-dir"]
terminal_title = ["project", "git-branch", "status"]
vim_mode_default = false
raw_output_mode = false
# interactively: /statusline /title /keymap /theme /personality
# core (model, sandbox, approvals, MCP) - from shared config layers, not IDE settings