[Bug] LaTeX math corrupted by markdown escaping and not rendered in terminal output

Status Open
Reported on v2.1.218
Maintainer reply None cached
Activity 3 comments · opened Jul 23, 2026

Bug Description
Title: Terminal corrupts and does not render LaTeX math in assistant output

Environment: Claude Code CLI, Windows 11, PowerShell.

Summary: Assistant messages containing LaTeX math are (1) shown as raw source instead of rendered, and (2) silently corrupted by GitHub-flavored-markdown backslash-escaping applied before display, which mangles LaTeX spacing macros.

Repro & evidence:

  1. Backslash-punctuation escaping (content corruption). The model emits $\forall\, \varepsilon$. It is displayed as $\forall, \varepsilon$ — the \, (LaTeX thin-space) has its backslash stripped, leaving a bare comma. Same failure for \;→;, \:→:, \!→!. Meanwhile \varepsilon, \forall, \ge keep their backslashes, because markdown only escapes ASCII punctuation, not letters. So the escaping is selective and corrupts exactly the spacing macros.
  2. No math rendering. The model emits $$f(n) = 2n, \qquad g(n) = n.$$. It is displayed verbatim as raw source — $$, \qquad and all — with no math typesetting.

Expected: Either render $...$ / $$...$$ as math, or at minimum pass their contents through verbatim (no backslash-escaping) so the source can be copied into a LaTeX renderer intact.

Actual: Math is not rendered, and backslash-punctuation escapes inside math spans are stripped, silently corrupting the LaTeX. The model emits correct source and cannot see the corruption; the user gets stray punctuation.

Impact: Math-heavy responses are hard to read in-terminal, and — worse — copy-pasting the raw source into a real LaTeX engine yields wrong output wherever spacing macros were used, with no visible warning.

Suggested fix: Treat $...$ / $$...$$ as math spans: skip markdown backslash-escaping inside them, and ideally render them (or fall back to a Unicode/plaintext math presentation).

Environment Info

  • Platform: win32
  • Terminal: WezTerm
  • Version: 2.1.218
  • Feedback ID: f64b4b12-cf46-49b0-be57-0edbff64731e

Errors

[]

View original on GitHub ↗

3 Comments

iCodeCraft · 2 months ago

I built an opt-in MessageDisplay plugin that preserves Markdown-sensitive LaTeX escapes in Claude Code terminal output:

It preserves commands such as \,, \;, \:, \!, and \\ in dollar-delimited LaTeX, so the source remains copyable. The transformation is display-only: it does not modify the transcript or model context, and it makes no network requests.

I verified the workaround end-to-end with Claude Code 2.1.220 on macOS/Kitty. The automated test suite also runs on macOS, Linux, and Windows with Git Bash. I have submitted the plugin to the Claude Code community marketplace for review.

This is a source-preservation workaround, not visual equation rendering; a built-in rendering or source-preservation fix would still be preferable. Feedback from a Windows/WezTerm setup would be especially valuable.

While implementing this workaround, I found that the bundled Hook Development skill did not cover the MessageDisplay event or its streaming semantics. I opened a separate documentation PR to address that gap: https://github.com/anthropics/claude-code/pull/83374

iCodeCraft · 1 month ago

Follow-up: I've since published mathshow, which takes a different angle on the same pain. The MessageDisplay plugin here preserves LaTeX-sensitive escapes in Claude Code's terminal output — still valuable for copy/paste fidelity. mathshow is agent-agnostic: when the user should see a formula, the agent runs:

npx --yes mathshow -- '<latex>'

→ KaTeX preview in the browser. Works with Cursor, Claude Code, Codex, and other agents via the Agent Skills format.

https://github.com/iCodeCraft/mathshow Still not a substitute for fixing markdown escaping at the TUI layer (this issue), but it sidesteps the rendering gap entirely. If you're on Windows/WezTerm, I'd love to know whether the plugin + mathshow combo covers your workflow.

lulu-loopp · 29 days ago

Adding evidence from the other side of the pipe. I maintain a terminal that typesets $…$ / $$…$$ in command output, so I see exactly which bytes Claude Code writes, twice: once while the answer streams, and once when the finished answer is redrawn through the markdown renderer. The streamed bytes are intact; the final redraw is where the LaTeX is changed. Beyond the spacing macros in the report above, three more rules bite:

  1. \\ → \. Every row separator inside pmatrix / aligned / cases loses one backslash, so a matrix that was valid a second earlier ends up with a stray \ at each line end and cannot be parsed by any TeX engine.
  2. \[ → [ and \] → ]. A display block delimited with brackets loses both delimiters.
  3. A line holding only = (an A x = b written across three lines of matrices) is taken as a setext underline: the paragraph above it becomes an H1 and the = line is deleted from the output. The equation then reads A x b.

Minimal reproduction (ask for exactly this, then compare the streamed text with the final redraw):

$$
\begin{pmatrix} a & b \\ c & d \end{pmatrix}
\begin{pmatrix} x \\ y \end{pmatrix}
=
\begin{pmatrix} ax + by \\ cx + dy \end{pmatrix}
$$

Final redraw as received by the terminal: the \\ become \, and the = line is gone with the lines above it styled as a heading.

Suggested fix, in order of cost: mask $…$, $$…$$, \(…\) and \[…\] spans before the CommonMark pass and restore them verbatim afterwards (this is what GitHub's renderer does, and what the Codex TUI started doing this week in openai/codex#45501 and openai/codex#45612, with a verbatim fallback for anything it cannot render). Rendering the math is optional; not altering it is the part that matters, because the bytes in the terminal are what gets copied, and what a terminal that can typeset them is given.

Observed with Claude Code 2.1.274 on Windows 11, in Folio (the terminal I maintain); the bytes are the same in any terminal, since the change happens before they are written.