[Feature Request] LaTeX rendering support in terminal output

Status Open
Reported on v2.1.92
Maintainer reply None cached
Activity 13 comments · opened Apr 7, 2026

Bug Description
PLEASE ALLOW LATEX TO RENDER IN THE TERMINAL PLEASE PLEASE IT WILL MAKE LEANRING CONCEPTS SO MUCH EASUER THIS WOULD BE HUGE

Environment Info

  • Platform: darwin
  • Terminal: Apple_Terminal
  • Version: 2.1.92
  • Feedback ID: 89f832ee-6067-4c40-9eb3-a6e8ef6aef01

Errors

[{"error":"Error: NON-FATAL: Lock acquisition failed for /Users/vkamarthi24/.local/share/claude/versions/2.1.92 (expected in multi-process scenarios)\n    at im_ (/$bunfs/root/src/entrypoints/cli.js:1884:2153)\n    at An6 (/$bunfs/root/src/entrypoints/cli.js:1884:1233)\n    at processTicksAndRejections (native:7:39)","timestamp":"2026-04-06T12:53:37.059Z"},{"error":"Error: 1P event logging: 1 events failed to export (code=ECONNABORTED, timeout of 10000ms exceeded)\n    at queueFailedEvents (/$bunfs/root/src/entrypoints/cli.js:422:2574)\n    at async doExport (/$bunfs/root/src/entrypoints/cli.js:422:1516)\n    at processTicksAndRejections (native:7:39)","timestamp":"2026-04-06T13:20:04.830Z"},{"error":"Error: {\"message\":\"Failed to export 1 events (code=ECONNABORTED, timeout of 10000ms exceeded)\",\"originalLine\":\"422\",\"originalColumn\":\"1668\",\"line\":\"422\",\"column\":\"1668\",\"sourceURL\":\"/$bunfs/root/src/entrypoints/cli.js\",\"stack\":\"Error: Failed to export 1 events (code=ECONNABORTED, timeout of 10000ms exceeded)\\n    at doExport (/$bunfs/root/src/entrypoints/cli.js:422:1668)\\n    at processTicksAndRejections (native:7:39)\",\"name\":\"Error\"}\n    at error (/$bunfs/root/src/entrypoints/cli.js:1822:4371)\n    at <anonymous> (/$bunfs/root/src/entrypoints/cli.js:417:36794)\n    at AZ4 (/$bunfs/root/src/entrypoints/cli.js:417:37338)\n    at <anonymous> (/$bunfs/root/src/entrypoints/cli.js:418:19103)\n    at processTicksAndRejections (native:7:39)","timestamp":"2026-04-06T13:20:04.831Z"},{"error":"Error: 1P event logging: 5 events failed to export (code=ECONNABORTED, timeout of 10000ms exceeded)\n    at queueFailedEvents (/$bunfs/root/src/entrypoints/cli.js:422:2574)\n    at async doExport (/$bunfs/root/src/entrypoints/cli.js:422:1516)\n    at processTicksAndRejections (native:7:39)","timestamp":"2026-04-06T13:23:57.612Z"},{"error":"Error: {\"message\":\"Failed to export 5 events (code=ECONNABORTED, timeout of 10000ms exceeded)\",\"originalLine\":\"422\",\"originalColumn\":\"1668\",\"line\":\"422\",\"column\":\"1668\",\"sourceURL\":\"/$bunfs/root/src/entrypoints/cli.js\",\"stack\":\"Error: Failed to export 5 events (code=ECONNABORTED, timeout of 10000ms exceeded)\\n    at doExport (/$bunfs/root/src/entrypoints/cli.js:422:1668)\\n    at processTicksAndRejections (native:7:39)\",\"name\":\"Error\"}\n    at error (/$bunfs/root/src/entrypoints/cli.js:1822:4371)\n    at <anonymous> (/$bunfs/root/src/entrypoints/cli.js:417:36794)\n    at AZ4 (/$bunfs/root/src/entrypoints/cli.js:417:37338)\n    at <anonymous> (/$bunfs/root/src/entrypoints/cli.js:418:19103)\n    at processTicksAndRejections (native:7:39)","timestamp":"2026-04-06T13:23:57.613Z"},{"error":"Error: 1P event logging: 1 events failed to export (code=ECONNABORTED, timeout of 10000ms exceeded)\n    at queueFailedEvents (/$bunfs/root/src/entrypoints/cli.js:422:2574)\n    at async doExport (/$bunfs/root/src/entrypoints/cli.js:422:1516)\n    at processTicksAndRejections (native:7:39)","timestamp":"2026-04-06T14:01:31.180Z"},{"error":"Error: {\"message\":\"Failed to export 1 events (code=ECONNABORTED, timeout of 10000ms exceeded)\",\"originalLine\":\"422\",\"originalColumn\":\"1668\",\"line\":\"422\",\"column\":\"1668\",\"sourceURL\":\"/$bunfs/root/src/entrypoints/cli.js\",\"stack\":\"Error: Failed to export 1 events (code=ECONNABORTED, timeout of 10000ms exceeded)\\n    at doExport (/$bunfs/root/src/entrypoints/cli.js:422:1668)\\n    at processTicksAndRejections (native:7:39)\",\"name\":\"Error\"}\n    at error (/$bunfs/root/src/entrypoints/cli.js:1822:4371)\n    at <anonymous> (/$bunfs/root/src/entrypoints/cli.js:417:36794)\n    at AZ4 (/$bunfs/root/src/entrypoints/cli.js:417:37338)\n    at <anonymous> (/$bunfs/root/src/entrypoints/cli.js:418:19103)\n    at processTicksAndRejections (native:7:39)","timestamp":"2026-04-06T14:01:31.181Z"},{"error":"Error: Failed to fetch version from https://storage.googleapis.com/claude-code-dist-86c565f3-f756-42ad-8dfa-d59b1c096819/claude-code-releases/latest: timeout of 30000ms exceeded\n    at Py1 (/$bunfs/root/src/entrypoints/cli.js:1882:15046)\n    at processTicksAndRejections (native:7:39)","timestamp":"2026-04-06T14:01:41.170Z"},{"error":"Error: Failed to fetch version from https://storage.googleapis.com/claude-code-dist-86c565f3-f756-42ad-8dfa-d59b1c096819/claude-code-releases/latest: timeout of 30000ms exceeded\n    at Py1 (/$bunfs…

Note: Content was truncated.

View original on GitHub ↗

13 Comments

water2078 · 5 months ago

Adding a more structured request here because this seems to be the right issue for it.

The main request is support for Markdown math rendering in the Claude Code terminal / TUI path, ideally for both:

  • inline math: $...$
  • block math: $$...$$

Concrete examples:

Inline:

$W = W_0 + BA$

Block:

$$
q^T k = (q^C)^T k^C + (q^R)^T k^R
$$

Right now these show up as raw Markdown / LaTeX source, which makes Claude Code much less useful for:

  • ML / math-heavy notes
  • paper reading
  • algorithm derivations
  • technical documentation with equations

I think even a limited first step would already help a lot:

  • parse common inline/block math patterns
  • render them into a terminal-friendly plain-text / Unicode normalized form
  • preserve block math as visually distinct blocks
  • avoid obviously broken spacing / escaping for common expressions

This does not necessarily require full browser-style MathJax/KaTeX rendering in the terminal. A normalized terminal-friendly rendering path would already be a meaningful improvement over raw source.

This is specifically about the terminal / TUI rendering path, not browser-based renderers.

farhan0167 · 5 months ago

is this being considered? Would be really usefully if implemented. +1-ing this

Doglovesfish · 4 months ago

I also have this problem. Plz support latex in vscode cc tui.

jncrenshaw · 4 months ago

I also really need this feature.
If you want STEM to take Claude seriously, you need to let Claude output in a way that's usable by professionals in those fields.
Right now, the only way to get LaTeX is to run Claude headless and pipe the output to something else to render it, or use your crappy mobile/browser apps. Both of which are terrible solutions, IMO.

cossio · 4 months ago

+1, would be nice to have. Google just added this:

Added LaTeX math rendering, enabling the CLI to display beautiful mathematical formulas directly in the terminal viewport. Set AGY_CLI_DISABLE_LATEX environment variable to turn off LaTeX rendering globally if desired.

See https://github.com/google-antigravity/antigravity-cli/releases/tag/1.0.4

vladimirrott · 3 months ago

For anyone who needs a stopgap while this stays open: I put together a small Claude Code skill, claude-math, that gets Claude to emit math as inline Unicode glyphs (∑, ≤, ℝ, x², ∫₀¹, set-builder, matrices, etc.) instead of LaTeX, so it is at least legible in the terminal today.

To be clear, it does not render LaTeX (that is exactly what this issue asks for). It just sidesteps the $...$ noise with Unicode that every terminal already displays, and it is copy/search safe (no math-alphanumeric styling codepoints).

Install:

/plugin marketplace add vladimirrott/claude-math
/plugin install claude-math@vladimirrott

Same skill also works in Codex CLI (claude-math install --codex, since Codex reads the same SKILL.md format).

Repo: https://github.com/vladimirrott/claude-math

Would still love native rendering here; posting this only as a workaround for people who need readable math in the meantime.

vladimirrott · 2 months ago

Quick update: claude-math is now on npm, so no clone or marketplace-add needed first, one command does it:

npx claude-math install          # Claude Code
npx claude-math install --codex  # Codex CLI

Published with provenance (claude-math@0.2.0, https://www.npmjs.com/package/claude-math). Verified on a clean machine: installs and enables the skill fine.

Still just the Unicode-glyph workaround, not the native LaTeX rendering this issue asks for, so I'm not suggesting this closes it. Just a ~10-second install now if you want readable math in the terminal today.

Repo: https://github.com/vladimirrott/claude-math

cc @vignankamarthi @water2078 @farhan0167 @Doglovesfish @jncrenshaw @cossio in case the one-line install helps in the meantime.

vladimirrott · 2 months ago

Pinging the folks who asked for this, so the update doesn't get buried: claude-math is now a one-line install (npx claude-math install, or --codex for Codex CLI). Details in my comment above. It's the Unicode-glyph workaround, not the native rendering this issue tracks.

cc @vignankamarthi @water2078 @farhan0167 @Doglovesfish @jncrenshaw @cossio

vladimirrott · 2 months ago

Small update for anyone using the stopgap here, and thanks in advance to everyone who kicks the tires. Your feedback is what shapes this.

Over on the Codex twin of this request (openai/codex#18906), @DanChai22 pointed out the real limit of a Unicode-only skill: it cannot render arbitrary LaTeX, and stacked bounds leak source. Fair hit. So claude-math 0.3.1 now handles the multi-char cases much better:

  • big-operator bounds render as a bracketed inline range: ∑[i=1..n], ∫[a..b], ∫[-∞..∞], lim[x→0]
  • multi-char and expression exponents use caret plus parens: x^(k+1), e^(iπ), with single-char staying a real glyph: xᵀ, A⁻¹
  • multi-char subscripts stay n_{s,r}, since the underscore reads more clearly as a subscript than bracket indexing

To be clear this is still the Unicode stopgap, not the native rendering this issue asks for. The real fix is a TUI that parses inline and block math, renders through a graphics backend when the terminal has one (Kitty, iTerm2, SIXEL), and falls back to readable Unicode or structured text otherwise (SSH, tmux, CI logs).

One line to try it, MIT, read every line:

npx claude-math install # Claude Code
npx claude-math install --codex # Codex CLI

Repo: https://github.com/vladimirrott/claude-math

Two open questions I would genuinely love your take on:

  1. the fallback layout for stacked bounds and integrals when there is no graphics backend
  2. Unicode-first by default, or always keep a raw-source toggle

@vignankamarthi @water2078 @farhan0167 @Doglovesfish @jncrenshaw @cossio what would you want from a native renderer here? And if you try the stopgap, thank you in advance for any feedback. That is exactly the kind of nudge that turned into today's fix.

Open source is at its best when someone points at the rough edge and it just gets fixed.

iCodeCraft · 2 months ago

A related terminal issue is LaTeX source corruption caused by Markdown backslash escaping, tracked in #80702.

I built and tested an opt-in MessageDisplay plugin that preserves LaTeX-sensitive escapes such as \,, \;, \:, \!, and \\ in dollar-delimited math, so the source remains copyable:

This is intentionally a display-only workaround: it does not alter the transcript or model context, and it does not provide visual equation rendering. So it is not a replacement for the native rendering requested in this issue, but it demonstrates that MessageDisplay can provide a safe interim path for preserving correct LaTeX source.

While implementing it, I found that the bundled Hook Development skill did not document MessageDisplay or its streaming semantics. I opened a small documentation PR for that gap: #83374.

vladimirrott · 2 months ago

Status update, since this issue and its Codex twin (openai/codex#18906) keep converging and the work is now split across both.

On the Codex side two native implementations exist as branches: @Neomelt's (typst + mitex, rasterised to Kitty graphics, statically linked, no TeX install required) and @ZealousEar's (system latex + dvipng, finalized display blocks only). Today @Juddd proposed the split that I think applies here too: Unicode-first, render-only, as milestone 1, with a graphics backend as milestone 2, citing Pi 0.84.0 and JCode as shipped prior art.

The architectural point worth importing into this issue: convert at the render stage only, and leave the transcript untouched. That preserves exact LaTeX for resume, export, copy and verification. It is also strictly better than what a skill or a prompt rule can do, because those change what the model emits and are therefore lossy at the source. I maintain one of those skills and I would still rather have the renderer.

@iCodeCraft your escape-preservation plugin and #80702 are the same root cause @Neomelt hit in Codex: CommonMark unescapes backslashed ASCII punctuation, so \,, \; and \\ are already destroyed by the time the renderer sees the event stream, and a * pair inside an equation becomes real Emphasis events that split the text run. Neither is recoverable afterwards, which is why extraction has to happen before Markdown parsing rather than after. #80702 and this issue cannot really be fixed independently.

Two data points for whoever picks this up, since "just add a Unicode fallback" is easy to underestimate. Checked programmatically against Unicode 15.0 data:

  • Subscripts exist for only 17 of 26 lowercase letters (ₐ ₑ ₕ ᵢ ⱼ ₖ ₗ ₘ ₙ ₒ ₚ ᵣ ₛ ₜ ᵤ ᵥ ₓ). There is no form for b c d f g q w y z, so x_c cannot be mapped at all.
  • There is no superscript ∞, so \int_0^\infty cannot render both bounds the same way. A bracketed range such as ∫[0..∞] is the only fallback that stays uniform, which also handles x^{k+1} and other multi-character bounds.

@vignankamarthi @water2078 @jncrenshaw @cossio @farhan0167 @Doglovesfish for visibility. Note that #63139 has been closed, so this is the live issue on the Claude Code side.

iCodeCraft · 1 month ago

Update for anyone still waiting on native TUI rendering. I still agree the right long-term fix is math parsing + rendering in the terminal path (or at least skipping backslash-escaping inside $...$ / $$...$$, per #80702). In the meantime I shipped mathshow — a portable workaround that doesn't depend on Claude Code hooks or a specific IDE:

npx skills add iCodeCraft/mathshow   # Agent Skill
npx --yes mathshow -- 'E = mc^2'     # KaTeX browser preview

The skill tells the agent: when the user should see a formula, run mathshow with real TeX — not Unicode glyphs, not a screenshot. https://github.com/iCodeCraft/mathshow This is explicitly a bridge until native rendering lands. Native TUI math would still be strictly better for in-session reading; mathshow is for when you want proper typesetting now across Cursor, Claude Code, Codex, etc. Feedback welcome, especially from folks doing ML/paper-reading workflows.

iCodeCraft · 1 month ago
Status update, since this issue and its Codex twin (openai/codex#18906) keep converging and the work is now split across both. On the Codex side two native implementations exist as branches: @Neomelt's (typst + mitex, rasterised to Kitty graphics, statically linked, no TeX install required) and @ZealousEar's (system latex + dvipng, finalized display blocks only). Today @Juddd proposed the split that I think applies here too: Unicode-first, render-only, as milestone 1, with a graphics backend as milestone 2, citing Pi 0.84.0 and JCode as shipped prior art. The architectural point worth importing into this issue: convert at the render stage only, and leave the transcript untouched. That preserves exact LaTeX for resume, export, copy and verification. It is also strictly better than what a skill or a prompt rule can do, because those change what the model emits and are therefore lossy at the source. I maintain one of those skills and I would still rather have the renderer. @iCodeCraft your escape-preservation plugin and #80702 are the same root cause @Neomelt hit in Codex: CommonMark unescapes backslashed ASCII punctuation, so \,, \; and \\ are already destroyed by the time the renderer sees the event stream, and a * pair inside an equation becomes real Emphasis events that split the text run. Neither is recoverable afterwards, which is why extraction has to happen before Markdown parsing rather than after. #80702 and this issue cannot really be fixed independently. Two data points for whoever picks this up, since "just add a Unicode fallback" is easy to underestimate. Checked programmatically against Unicode 15.0 data: Subscripts exist for only 17 of 26 lowercase letters (ₐ ₑ ₕ ᵢ ⱼ ₖ ₗ ₘ ₙ ₒ ₚ ᵣ ₛ ₜ ᵤ ᵥ ₓ). There is no form for b c d f g q w y z, so x_c cannot be mapped at all. There is no superscript ∞, so \int_0^\infty cannot render both bounds the same way. A bracketed range such as ∫[0..∞] is the only fallback that stays uniform, which also handles x^{k+1} and other multi-character bounds. @vignankamarthi @water2078 @jncrenshaw @cossio @farhan0167 @Doglovesfish for visibility. Note that #63139 has been closed, so this is the live issue on the Claude Code side.

Thanks for the ping and for laying out the render-stage vs skill distinction — agree completely, especially on extraction before Markdown parsing (#80702). I posted an update just now on mathshow, which takes a different interim path: the agent keeps emitting real TeX, but runs mathshow → KaTeX in the browser instead of changing output to Unicode or relying on Claude Code hooks. Still a bridge, not native TUI rendering. Would love your take if you try it alongside claude-math.