Data · 13 min read

What AI Actually Writes: A Markdown Census of 1.44 Million Messages

We scanned 1,437,389 real assistant messages. Models write almost entirely inside core CommonMark and GFM — and turned the formatting up a hundredfold in two years.

The last post ended with a question. If humans can’t keep Markdown’s flavors straight, what about the machines now writing most of it? Models emit an enormous volume of Markdown every day — into chat windows, IDEs, and files people then have to read somewhere else. As far as we can tell, nobody had measured what’s in it. There are benchmarks for whether a model can produce good Markdown, and there are vendor docs full of examples, but no published count of what models actually emit in ordinary use.

So we counted. We scanned 1,437,389 assistant messages from three public datasets of real user–model conversations, spanning April 2023 to July 2025 and thirty-odd models, and tallied every Markdown construct in every message.

The short version: models write inside the ring, almost entirely. A plain CommonMark plus GFM renderer covers more than 99.7% of what they emit. The features that fill Markdown editor marketing pages — callouts, wikilinks, front matter, footnotes — are close to nonexistent in real model output. GitHub-style callouts appeared in exactly one message out of 1.44 million.

But the volume of formatting inside the ring exploded. GPT-3.5 in April 2023 bolded something in 0.44% of its messages. GPT-4.1-mini in mid-2025 does it in 40.21%. The ring didn’t get wider. The models moved into it and turned the formatting up a hundredfold.

A cliff-shaped distribution of Markdown constructs, with lists, code and bold towering over a long flat tail of unused extensions.
The distribution has a plateau and a cliff, and almost nothing in between.

First, the way not to do this

Our first attempt at this was a survey of published model outputs: vendor cookbooks, API documentation, official example galleries. It produced a tidy result — 25 samples, zero Markdown tables — and it was worthless.

Vendor documentation is curated to demonstrate an API, so it selects heavily for short code examples and simple question answering. And 25 samples cannot resolve a rate near 1% in any case: if the true rate were exactly 1%, a 25-sample study would see zero tables 78% of the time. The honest conclusion from that pilot was not “models rarely emit tables.” It was “this method cannot answer this question.”

The method that can answer it is unglamorous: take datasets of real conversations and scan every assistant message exactly the same way. The pattern rules and checks are described below.

The data

Three public datasets of real user–model conversations, assistant replies only:

DatasetConversationsPeriodMessages scanned
WildChat-4.8M (6 of 86 parts)223,246Apr 2023 – Jul 2025406,852
LMSYS-Chat-1M (2 of 6 parts)333,333Apr – Aug 2023662,762
ShareGPT V394,145Mar – Apr 2023367,775
Total650,724Apr 2023 – Jul 20251,437,389

Thirty-plus distinct models: GPT-3.5 through GPT-4.1-mini, o1-preview and o1-mini, Claude 1 and 2, PaLM 2, and the 2023 open-weight cohort — Vicuna, Koala, Alpaca, Llama 2, MPT, WizardLM and the rest.

The scanner works in two passes. The first finds every fenced code block, following CommonMark’s rules — a fence closes only on a fence of the same character whose length is at least the opener’s — and removes everything inside a fence from the text before anything else is counted. That single decision is what separates this from a simple text search: a # comment inside a Python block is never counted as a heading, and ** in Python exponentiation is never counted as bold. The second pass matches each remaining construct in turn, removing it as it’s found so nested constructs aren’t double-counted.

We checked the scanner against 28 hand-labelled examples covering every construct plus the tricky edges — a fence inside a fence, tilde fences, 12:30:45 not being an emoji shortcode, $5 and $10 not being math, --- as front matter versus horizontal rule versus heading underline. The checks caught a real bug before the full run: a mistyped pattern in the fence-matching code marked every fence as unclosed and swallowed the tail of every message. Every number below comes from the corrected rerun.

At 1.44 million messages, random noise is not the limiting factor anywhere in this post — the headline table rate is pinned down to within 0.02 percentage points. What these datasets happen to contain is the limitation, and we return to it at the end.

What AI Markdown is made of

Everything that appears in at least one message per thousand:

ConstructLayer% of messagesOccurrences per 1,000 messages
Ordered list itemCommonMark19.840%1346.7
Fenced code blockCommonMark17.845%295.3
Language-tagged fenceCommonMark14.330%227.0
Inline codeCommonMark11.392%820.2
Unordered list itemCommonMark9.199%918.5
BoldCommonMark6.004%471.0
H3 headingCommonMark3.115%135.9
Horizontal ruleCommonMark2.351%107.2
Nested list itemCommonMark1.589%162.5
GFM pipe tableGFM1.007%12.6
ItalicCommonMark0.886%37.3
H2 headingCommonMark0.537%19.9
Bare URLGFM0.469%10.5
AutolinkCommonMark0.453%14.3
Markdown linkCommonMark0.405%12.8
H4 headingCommonMark0.391%15.6
H1 headingCommonMark0.287%8.9
Raw HTMLCommonMark0.271%11.9
Indented codeCommonMark0.168%13.5
Inline mathnot GFM0.107%6.4

That is the whole visible surface. Below inline math, nothing else reaches one message in a thousand.

Everyday AI Markdown is lists, code, and bold. Those three account for most of it — and the code is almost always labelled, with 77% of fences carrying a language tag. Then, right around 1%, there is a cliff.

Two things in the table are worth pausing on before the rest of the post.

Ordered lists beat unordered lists two to one. In human-written Markdown it runs the other way; bullets are the default and numbers are for genuine sequences. Models number things because they are answering step by step, and because an enumerated answer reads as more complete. It is the clearest fingerprint of machine-written Markdown in the dataset.

Horizontal rules are the eighth most common block construct, in 2.35% of messages — more common than tables. Models use --- on its own line as a divider between sections of a long answer. No spec suggests this; they picked it up from prose that used it that way.

Outside the ring is empty

Post 2 was a tour of everything outside core CommonMark and GFM — footnotes, math, Mermaid, callouts, wikilinks, YAML front matter — and how each fails when a file moves between tools. Every one of those is a headline feature on some Markdown editor’s landing page. So how often do models actually emit them?

Construct% of messagesMessages
Inline math $…$0.107%1,532
Display math $$…$$0.024%346
Mermaid fence0.017%241
Wikilink [[x]]0.014%204 (mostly false alarms)
Emoji shortcode :name:0.009%123
Footnote marker [^1]0.004%56 (mostly false alarms)
==highlight==0.003%43
Footnote definition [^1]:0.0004%6
YAML front matter0.0003%4
> [!NOTE] callout0.0001%1

One message. Out of 1,437,389, exactly one contained a GitHub-style callout, and it was a 2023 Vicuna response using > [!important].

Real footnotes are barely more common. The 56 messages with a [^1]-shaped marker are a worst-case count and mostly false alarms — search patterns such as [^万] in code that slipped past the fence stripper. Messages containing an actual footnote definition number six. That is one message in 240,000.

Wikilinks tell the same story: roughly 70% of the flagged samples were NumPy matrix literals [[1,2],[3,4]] or JavaScript’s [[Prototype]]. Genuine [[wiki links]] from a model are close to unmeasurable.

Only math has real mass, and even it sits near one message in a thousand. Math is also the one construct that moves against the general trend: it is highest in GPT-3.5- and ShareGPT-era messages (0.179%) and lower for GPT-4o (0.057%), because $-delimited math tracks how many users are doing homework, not how new the model is.

So the conclusion is blunt. A renderer that implements CommonMark plus GFM correctly handles more than 99.7% of what models emit. If you want to spend effort beyond that, spend it on math, then stop.

A vast grid of message squares with a single one highlighted, representing one callout found in 1,437,389 messages.
The features Markdown editors advertise hardest are the ones models never learned.

Why models never picked up the rest is a question this data can’t settle, but the shape of it is suggestive. The constructs models use fluently are the ones that saturate public technical text — GitHub, Stack Overflow, documentation sites. The ones they skip belong to tools whose documents are mostly private, or whose syntax only ever meant anything inside one app. That is a hypothesis, not a finding; testing it would need a dataset of what models were trained on, which nobody has.

GFM’s own extensions are barely used either

The surprise is that the cliff isn’t at the CommonMark/GFM boundary. It’s inside GFM.

GFM adds four things to CommonMark: tables, strikethrough, task lists, and extended autolinks. Only tables and autolinks see real use. Strikethrough appeared in 14 messages. Task lists in 62. They are rarer than emoji shortcodes.

So the working ring — the set of constructs that appear in machine-written Markdown at any rate worth engineering for — is smaller than the one post 1 drew. It is CommonMark, plus tables, plus autolinks. The rest is rounding error.

The volume, though, exploded

How much models format is not a fixed property of “AI output.” It depends on when the model was made.

Model (dataset, period)BoldH3TablesBulletsFenced code
GPT-3.5 (Apr 2023)0.44%0.05%0.21%4.31%12.57%
GPT-4 (Apr 2023)1.41%0.16%0.45%7.83%20.36%
GPT-4 Turbo (Feb–Mar 2024)23.86%3.09%0.31%20.93%14.81%
GPT-4o (Oct–Nov 2024)16.38%8.10%0.20%10.82%48.09%
GPT-4o mini (2024–25)34.77%20.61%0.40%18.54%47.66%
o1-mini (Nov 2024)82.61%61.94%2.28%72.06%48.06%
GPT-4.1 mini (Mar–Jul 2025)40.21%28.38%4.80%35.09%23.53%
Claude 1/2 (2023)0.40%0.03%0.22%16.69%12.10%
Vicuna (2023)0.26%0.06%0.38%5.15%10.33%
Koala (2023)0.14%0.22%0.02%3.78%5.67%

Bold goes from 0.44% to 40.21% across essentially one product line in two years. H3 headings go from a rounding error to more than a quarter of all messages. o1-mini bolds something in 82.61% of its messages and opens an H3 section in 61.94% — a reasoning model narrating its own structure out loud.

The 2023 baseline is the part that’s hard to remember now. GPT-3.5 wrote nearly plain text. So did Claude 1 and 2, at 0.40% bold and 0.03% H3. So did every open-weight model of that era. The heavily formatted answer — bolded lead-in, ### section headers, bulleted summary, closing table — is a 2024–2025 invention.

Two chat answers side by side: a nearly plain 2023 response and a heavily structured 2025 response using the same Markdown syntax.
Nothing in the syntax changed between these two. Only the models did.

One caution on reading that table: bold and headings are close to a pure model signature, but the fenced-code column is tangled up with who was using the model. GPT-4o’s 48% code rate partly reflects how developer-heavy the 2024 WildChat users were.

The practical consequence stands regardless. Anything built and tested against 2023-era model output underestimates how heavily formatted today’s answers are by roughly three to ten times, and the trend was still climbing at the end of our window. Every number in this post is a floor for what a 2026 frontier model emits.

What the question changes

Formatting also depends on what was asked. Splitting by the genre of the opening user message:

GenreFenced codeTablesBoldOrdered lists
Code64.59%0.67%9.73%15.02%
Data analysis30.62%1.83%10.71%18.00%
Explanation10.48%0.90%4.35%24.08%
Writing2.29%0.60%2.32%11.30%
Roleplay4.22%1.19%5.39%9.73%

Coding questions produce fenced code in nearly two-thirds of answers and suppress tables. Data-analysis questions produce the most tables of any genre, at nearly double the overall rate. Explanation questions produce the most numbered lists. Writing and roleplay are the plainest categories in the data — when a model is producing prose for a human to read as prose, it mostly stops formatting.

This one comes with a real caveat: the sorting is a simple keyword check on the first user message, 71% of conversations land in a leftover “other” bucket, and multi-turn conversations keep whatever label they started with. Read the genre rows as rough directions, not exact measurements.

Models write Markdown like machines, not like people

Three habits in the data have no equivalent in human-written Markdown.

They start outlines at H3. H3 appears in 3.115% of messages, H2 in 0.537%, H1 in 0.287%. Where a message has headings at all, the deepest one is H3 in 80.7% of cases and H4 in 11.2%; H5 and H6 barely exist. Models behave as if the chat answer were already nested inside some implicit document whose title and top-level sections belong to someone else — which, inside a chat bubble, is arguably correct. It does mean heading levels in model output carry no absolute meaning, only relative structure. Anything building a table of contents from model output has to normalize first.

They use --- as furniture. At 2.35% of messages, the horizontal rule outranks tables. Models emit it between sections as a visual break. But CommonMark reads --- as a heading underline when it directly follows a line of text, and as a divider only after a blank line. The same habit therefore renders two different ways in two parsers that both follow the spec, depending on a blank line the model may or may not have produced.

They leak their own chat template. In 0.223% of messages — 3,200 of them, concentrated in 2023 open-weight models — we found ### Human: or ### Assistant: pseudo-headings. These are perfectly valid Markdown headings, and any parser that follows the rules dutifully renders them as such. They are not document structure; they are the model’s prompt format bleeding into its output. In LMSYS, 97% of all H3 lines are this artifact rather than real content structure.

What actually breaks a parser

Everyone worries about nested fences: a fenced code block containing another fenced code block, which simple parsers mis-pair. We measured it. A fence-like line inside a fenced block occurs in 0.035% of messages. The explicit four-backtick idiom — wrapping a triple-backtick example in a longer fence — appears in 56 messages out of 1.44 million. It is not the problem.

The problem is fences that never close. 0.618% of all messages contain an unclosed fence: 3.46% of every message that contains code at all. One in twenty-nine code answers ships a block that opens and never terminates, from truncated generations and from models that simply forget.

A code block whose opening fence is never closed, swallowing the prose, list and table that follow it in the message.
An unclosed fence doesn't break one block. It consumes everything after it.

That is the difference between a parser and pattern matching. A parser that follows CommonMark handles an unclosed fence exactly as the spec says — the block runs to the end of the input, and the remainder renders as code. A parser that splits on triple backticks, or pairs openers with closers, corrupts everything after that point. The constructs that break simple parsers are precisely the ones the spec already defines a fallback for.

A note on the LMArena numbers

There is one published measurement worth reconciling with. A working paper by El Hadi Caoui, analyzing 128,850 English LMArena battles, found that responses containing a Markdown table rose from 2% in mid-2024 to 10% in April–July 2025, with headings rising from 0.72 to 3.39 per response and bold blocks from 6.23 to 17.95.

Our organic numbers are far lower. Tables appear in 1.01% of messages overall, 0.20% for GPT-4o, and 4.80% for GPT-4.1-mini, the newest model in our sample — against LMArena’s 10%.

Part of that is model mix: Caoui’s 2025 window includes o3, o4-mini and Gemini 2.5 Pro, which our data doesn’t reach. Part is length; LMArena responses grew from 563 to 995 tokens over the same period, and a longer answer has more room for a table. But the gap is wide enough to be interesting on its own, because LMArena is not an ordinary chat product. It is a voting arena, and there is good published evidence that human voters reward length and visible structure — LMArena’s own operators found that controlling for length and Markdown counts reshuffled their leaderboard.

We won’t try to split the difference here. Nobody has, and the honest state of the evidence is that the cause is clear but the size of it hasn’t been measured. It is, however, the next thing worth writing about.

Limits

The dataset ends in July 2025. It contains no Claude 3 or 4, no Gemini, no DeepSeek and nothing GPT-5-class, because no large public dataset of genuine user–model conversations is newer than WildChat-4.8M. Given the upward trend, treat every average in this post as a floor rather than a current estimate.

Each dataset is skewed in its own way. WildChat users got free GPT access in exchange for logging, which attracts cost-conscious power users. ShareGPT is conversations people chose to share because they found them impressive. LMSYS is disproportionately people stress-testing open models, and our slice of it is 49% Vicuna, which is why its combined numbers don’t represent any real deployment. Prefer the per-model table over the overall average.

The scanner uses documented pattern rules rather than a full CommonMark parser. The noisy constructs — footnote references, wikilinks — are reported as worst-case counts with their false-alarm rates stated, which is why the real numbers for those are lower than the table rows.

All three datasets store raw model text, before any app renders it. That is the right choice for this question — we want what models emit, not what a frontend displays — but it means constructs an app would silently repair, unclosed fences above all, appear here in their raw, parser-breaking form.

So what

If you build anything that consumes model-written Markdown, the roadmap falls out of the data. Implement CommonMark and GFM properly, fence handling included, and you have covered 99.7% of your input. Add $-delimited math and you have covered the rest. The forty-extension feature list on a Markdown editor’s landing page is answering a question models don’t ask.

What’s left is doing the common cases perfectly, which is a smaller surface than it looks and one almost nobody gets entirely right — tables that survive a narrow screen, code blocks that don’t corrupt when a fence never closes, headings that normalize when the model starts at H3. That is most of what we spend our time on in Alku, and this scan is why: the range of what models emit is narrow, so there is no excuse for handling it badly.


Which brings us to the failure list. One in twenty-nine code answers has a fence that never closes. 2.35% of messages use --- in a position where two parsers that both follow the spec disagree about what it means. A good fraction of the headings in older model output aren’t headings at all. Next post, we take the same 1.44 million messages and go through what breaks, construct by construct.