Improve terminal Markdown rendering for wide mixed-language math/table output
What variant of Codex are you using?
codex-cli 0.141.0
What feature would you like to see?
Title
Improve terminal Markdown rendering for wide mixed-language output, display math-like blocks, and tables
Body
What problem are you seeing?
Codex CLI already does some terminal formatting, but long mixed-language technical answers can become hard to read in the TUI, especially when the response contains:
- Chinese + English mixed text
- math-like LaTeX snippets
- wide tables
- long inline expressions
- wrapped paragraphs inside a narrow terminal
This is mostly a rendering/readability issue. The content is correct, but the terminal presentation is sometimes much harder to scan than the same answer rendered as Markdown in a web UI.
One representative example. I am using an English example here to keep the issue easy to review, but the same rendering problem is more visible with CJK text and mixed-width characters:
A four-bar linkage is a simple example. Physically it only has 1 degree of freedom, but if it is described with 4 joint angles
(\theta_1,\theta_2,\theta_3,\theta_4), the configuration has to satisfy an additional loop-closure condition:
[
g(\theta)=0
]
This kind of constraint directly restricts the configuration, so it is a holonomic constraint. If the original configuration has
(n) variables and there are (k) independent holonomic constraints, the effective dimension is:
[
n-k
]
Taking the time derivative gives:
[
\frac{\partial g}{\partial \theta}\dot{\theta}=0
]
This can be written in the unified form:
[
A(\theta)\dot{\theta}=0
]
This is a Pfaffian constraint: a linear constraint at the velocity level.
The key point is that not every velocity constraint can be integrated back into a configuration constraint.
A car is the classic example. It can move forward, backward, and turn, but it cannot instantaneously slide sideways. Its velocity
constraint is:
[
\dot{x}\sin\phi-\dot{y}\cos\phi=0
]
Another related case is wide table output:
| Type | What it constrains | Does it reduce C-space dimension? | Example |
|---|---|---|---|
| configuration constraint / holonomic constraint | configuration itself (q) | yes | four-bar linkage loop closure |
| velocity constraint / nonholonomic constraint | velocity (\dot q) | not necessarily | a car cannot slide sideways |
In a narrow terminal, this kind of table is difficult to read if it is only wrapped as text or rendered as a very wide table.
Why this matters
Codex is often used for technical explanations, code reviews, math-heavy reasoning, and project planning. In those cases, the final answer may be correct but hard to consume because of terminal layout limitations.
The issue is especially visible for CJK users because terminal rendering has to account for display width, not just character count. Mixed Chinese, English, inline code, and math-like text can produce awkward wrapping.
Expected behavior
It would be helpful if Codex TUI could render final assistant messages with better terminal-aware Markdown handling:
- Preserve math-like blocks instead of showing them as plain bracketed lines where possible.
- Render GitHub-style Markdown tables more readably.
- Use
wcwidth-aware measurement for CJK/mixed-language text. - Fall back to a row-card layout when a Markdown table is wider than the terminal.
- Preserve inline code and backslash-heavy expressions such as
\dot q,\theta, and\frac{...}{...}.
For the table above, a narrow terminal fallback could be:
row 1
Type: configuration constraint / holonomic constraint
What it constrains: configuration itself (q)
Does it reduce C-space dimension?: yes
Example: four-bar linkage loop closure
row 2
Type: velocity constraint / nonholonomic constraint
What it constrains: velocity (\dot q)
Does it reduce C-space dimension?: not necessarily
Example: a car cannot slide sideways
This is usually easier to read than forcing a wide table into a narrow terminal.
Suggested implementation direction
I understand from the contributing guide that external code contributions are currently by invitation only, so I am opening this as a feature request / design suggestion rather than an unsolicited PR.
Possible low-risk rendering improvements:
- Detect GitHub-style Markdown tables in final assistant messages.
- Estimate table width using display width rather than string length.
- Render normally if the table fits the terminal.
- Fall back to row-card layout if the table is too wide.
- Preserve inline Markdown in cells where possible.
- Treat math-like bracket blocks as preformatted or display-math-style blocks.
The core heuristic could be:
if markdown_table_width <= terminal_width:
render as terminal table
else:
render each row as a key-value card
This would avoid making the normal case heavier while improving wide mixed-language tables.
Prototype
I tested a small local sidecar prototype that wraps codex exec --json, extracts the final assistant message, and renders it with Rich Markdown plus a custom Markdown table fallback:
codex exec --json ...
-> final agent_message
-> Markdown renderer
-> wcwidth-aware table width estimate
-> wide table fallback to row cards
This is not a replacement for the official TUI. It is only a proof of concept that the readability improvement is noticeable for mixed Chinese/English/math/table output.
The most useful part of the prototype was not “adding table borders”; Codex already has some terminal formatting. The useful part was:
- final-answer re-rendering after generation completes
- CJK display-width-aware table measurement
- wide-table fallback to cards
- preserving inline code and backslashes in math-like snippets
Environment
Please let me know what information would be most useful here. I can provide:
- terminal width
- terminal emulator
- Codex CLI version
- example prompts
- before/after screenshots or text captures
- a minimal fixture Markdown file for rendering tests
Related issues
This seems related to existing Markdown rendering requests such as:
- Improve Markdown rendering
- Support Markdown table rendering in Codex CLI
- Render markdown for plan responses
I am happy to move this to an existing issue if that is preferred.
Additional information
_No response_
2 Comments
Thanks for the thorough write-up. A lot of what this issue asks for already exists in
codex-rs/tui, so here is a mapping of the asks onto what is shipped, plus the one realgap and an honest note on the math piece.
## Already implemented in
codex-rs/tuiThe markdown renderer lives in
tui/src/markdown_render.rs(built onpulldown-cmark)with a key/value fallback in
tui/src/markdown_render/table_key_value.rs. It alreadycovers most of the "Expected behavior" list:
unicode-width(
UnicodeWidthStr/UnicodeWidthChar) is used throughout, and wrapping goes throughtextwrap's display-width measurement. CJK and other wide characters are measured bydisplay width, not character count, so mixed-width text is accounted for.
Options::ENABLE_TABLES. Columns are classified as Narrative (prose), TokenHeavy(paths, URLs, hashes), or Compact (short values), and width is shrunk by priority so an
oversized path or URL gives up space before readable prose collapses.
presented in useful chunks, body rows are transposed into "Key: Value" records
separated by muted rules. This is exactly the
if table_width <= terminal_width: grid else: cardsheuristic in your suggestion, withsome extra handling for partially starved cells.
\dot q,\theta, and\frac{...}{...}survive intact inside backticks.This landed across #22052, #24489, #24636, and #24825.
So the table readability, wcwidth measurement, and row-card fallback parts of this
request look complete today. If you have a specific narrow-terminal input that still
overflows or wraps badly, a minimal fixture would be the most useful thing to attach,
since that can go straight into a snapshot test.
## The real gap is math, and it is larger than it looks
Two separate problems stack here:
pulldown-cmark0.10, which has noENABLE_MATHoption and noInlineMath/DisplayMathevents. Those arrived in 0.11. Adding$/$$math support thereforerequires bumping a shared workspace dependency to 0.11, which is a breaking change
(for example
Tag::BlockQuotegains aBlockQuoteKindfield, so existing match armsin the renderer stop compiling) and re-verifying the renderer test and snapshot suite.
That is a maintainer call, not a drive-by change.
bare
[ ... ]and( ... )rather than$$ ... $$or\[ ... \]. No CommonMarkparser treats bare brackets as math, so even after a 0.11 upgrade with math enabled,
this exact output would still render as plain text. Detecting it would need
bare-bracket heuristics, which risk false positives on ordinary prose like
"see step [3]".
The cleaner direction for the bracket case is to emit proper
$$delimiters upstream sothe standard path can handle it, rather than guessing at bare brackets in the renderer.
## Suggested next step
The one low-risk improvement that needs no dependency change is CJK / mixed-width
snapshot test coverage. The width primitives are already correct, but there are
currently no CJK or full-width test cases, so these tests would either confirm the
existing behavior already satisfies the readability concern here, or surface a concrete
bug to fix. Either outcome closes the CJK part of this issue with evidence.
I understand contributions are invitation-only, so I am flagging this as a scoped
direction rather than opening a PR unprompted. Happy to put up the CJK tests if that
would be welcome, and to discuss whether a
pulldown-cmark0.11 upgrade is on the tablefor math support.
Thanks for the detailed clarification. That answers my main technical questions.
It sounds like the table rendering, CJK/mixed-width measurement, inline code preservation, and wide-table key/value fallback are
already implemented in
codex-rs/tui. The remaining example I noticed is mostly about math-like output sometimes being emitted asbare bracket blocks, which is not standard Markdown math and should not be guessed by the renderer.
I’ll close this broad issue for now.
One broader UX note: even with the existing TUI renderer, Codex CLI output can still feel noticeably less readable than the web UI
for long technical answers, especially when the answer mixes prose, equations, tables, and code. I understand this may be partly
due to terminal constraints rather than missing renderer features. If I run into a concrete narrow-terminal fixture where the
current renderer behaves unexpectedly, I’ll attach a minimal repro or open a more specific issue.
Thanks again for the thorough explanation.