Formatted answers and coloured code
Replies render as markdown: headings, lists, tables, quotes and fenced code. Code is coloured the way VS Code colours it, in every language VS Code's grammars cover, and so are shell commands in a tool card's header and the lines of a diff.
Why you would use it
A phone screen is small. A wall of unrendered markdown with ** and backticks
in it costs more to read than the answer is worth, and a 40-line file printed by
Read is unusable without a gutter and colour.
How to use it
Nothing to switch on. It applies to every reply, every tool output and every patch.
Read the reply.

Tap the copy icon in a code block's header bar to copy just that block.
Tap a link to open it in a new tab. A link to a file, such as
[format.js:9](src/format.js:9)or the inline codesrc/format.js:9, opens the file in the viewer instead, scrolled to the line it names.
An edit renders the same way, as a patch:

What you see
Rendered from an answer: headings (four levels), bullet and numbered lists
including nested ones, tables (a wide one scrolls sideways inside the card),
blockquotes, horizontal rules, **bold**, *italic*, ~~strike~~, inline
code, and links. A bare URL becomes a link, and so does a bare host:port (the
shape a dev server prints), and a web address written without https://, such
as paddle.com/retain, in prose or in backticks. A link inside bold, italic or
strikethrough is still a link.
A markdown link whose target is a path rather than a web address is a file link.
So is inline code that holds only a path: one with a / in it, or a file name
such as README.md, .env or Dockerfile, with or without a line. npm test
or parseInline stays plain code. A long press on a file link selects its text.
The path is read from the thread's folder; an absolute path outside it opens
from /, and a path starting ~/ opens from your home folder on the tab's
workstation. A line given as :42, :42:7 or #L42 scrolls the viewer to that
line.
A fenced code block gets a header bar showing the language (or text) and a
copy button. A fence with no language is guessed: shell when the content is
commands, otherwise from the content.
Tool output is decided in this order: an MCP envelope is unwrapped, real escape
bytes claim the terminal renderer, then structure (a numbered Read listing
keeps its line-number gutter, grep hits keep theirs, fenced blocks are split out),
and only then language, taken from the title's extension when the body could
plausibly be that file.
A diff renders as three columns: line number, +/− marker, and the content
coloured as the language of the file being changed. Line numbers appear only
when the patch carries an @@ header; claude reports edits as old/new strings,
so its synthesized patches have none.
Options and settings
| Option | Default | What it changes |
|---|---|---|
| fence language | guessed | the label on the block and the colours used |
Every language VS Code's grammars cover has colours, over 240. A fence takes
the language's name or one of its short names, such as ts, py, sh or
rs. A name no grammar knows renders as one plain block.
A block shows plain first and takes its colours a moment later. The first
block in a language waits for that language's colours to download; after that
they are kept on the device. Offline, a language you have never seen shows
plain. JavaScript, TypeScript, JSX, TSX, shell, Python, JSON, CSS, HTML, YAML,
SQL, Markdown, INI, TOML, .env and diffs come with the app and colour offline
from the start. While an answer streams, its growing code block is coloured
again at most every 300 ms.
Limits and known gaps
- Images render only from VCode's own screenshots folder. See inline-screenshots.
- HTML in an answer is never interpreted. Every node is built from the DOM API,
never from
innerHTML, because agent output is untrusted text. - Underscores inside a word do not become italics.
- A path in plain text, outside backticks, is not a link. A folder path (ending
in
/) is not one either. - Whether the file exists is not checked until you tap. A path to a file that
is not there looks like a link, and a tap on it does nothing. A file that takes
more than a quarter of a second to read (a big one, from the app) opens the
viewer showing
reading…while it loads; if the read then fails, the viewer closes and a toast says why. - An address without
https://is a web link only when it is in lowercase and ends in one ofcom,org,net,dev,io,ai,co,gg,xyz,cloud,edu,gov,us,uk,eu,de,fr,caorau, so file names such asserver.pystay text. Any other bare domain, such as[site](example.app), is taken as a file, and a tap on it does nothing. ~user/in a file link is not expanded; only~/is.- An unclosed fence is treated as code to the end of the text, because that is the normal state of a streaming answer.
.htmlin a tool title is a weak claim: when a body looks like script rather than markup, the language guessed from the content is used instead.- A block over 20,000 lines or 1 MiB stays plain.
golangandsvgas a fence's name stay plain;goandxmlcolour.
Related
- terminal-output-and-links: ANSI colour and one-tap link copy
- copy-from-the-transcript: the copy buttons
- file-viewer: where a file link opens
- run-a-command-from-a-code-block: the run control on bash blocks
- read-the-transcript: the cards this renders into
- inline-screenshots: the one image source markdown will render
- diff-review-sheet: the whole patch, not the card's first lines
- file-viewer: the same colouring over a whole file
- open-the-app-offline: which languages keep their colours offline