Skip to content

ADR-0006: Exclude content/docs MDX files from Prettier

Listen to this page5:08
Read the transcript

1. Six pages, silently corrupted

Host: So we’re digging into ADR-0006 today, and the setup is almost comic if it weren’t so nasty: six pages across your Learn module — Modules 1, 2, 4, 5, 6, and 7 — had Python code examples that just silently stopped being valid Python. Not a crash, not a warning, just quietly broken. Walk me through what actually happened.

Guest: Right, so these code examples weren’t sitting at the top level of an MDX file — they were nested inside a custom JSX/MDX component we use for walkthroughs. Someone ran pnpm format, which runs Prettier across the repo, and Prettier rewrote several of these nested fences: it stripped indentation off lines that came after a blank line inside the fence, merged comments onto the previous line of code, and it backslash-escaped underscores and asterisks in identifiers like __init__ and self._admit because it treated them as Markdown emphasis syntax instead of code.

Host: And none of that got caught anywhere in CI, which is the part that really stings — pnpm format and pnpm build ran fine, right through it.

Guest: Exactly, neither of those checks the actual contents of a fenced block against its declared language, so mangled Python sailed straight through. The only content-specific check we had was a lint script validating required headings and frontmatter — nothing was ever looking inside the fences, so there was no seatbelt at any layer for this.

2. Three ways out, and why two don’t hold

Host: So once you know nothing’s watching inside those fences, you’ve got three ways to respond. Walk me through them, starting with the one that feels cheapest.

Guest: Cheapest is just declaring a rule: never put a blank line inside a nested fenced code block. But that’s a landmine with no lint rule behind it — some future contributor who doesn’t know the rule hits the trigger, and gets silently corrupted code instead of a formatting diff. A failure mode that severe can’t rest on people remembering a rule nobody wrote down anywhere enforceable. The second option is ripping out CodeWalkthrough and similar components so every fence lives at the top level, which does dodge the bug, but it throws away the narrative framing those components give for every future example in the handbook, not just the six that got hit.

Host: So one option is unenforceable, and the other is a permanent tax on every doc author going forward. What made the third option — excluding content docs from Prettier entirely — the obvious landing spot?

Guest: Because it matches the actual severity: authors already hand-format code inside those fences since they’re excerpts from real source, not generated output, so Prettier touching them was never adding value, just risk. Excluding the docs MDX means we only lose automatic formatting of prose and JSX outside the fences — purely cosmetic — while removing the one thing that could silently mangle real code. Once nothing inside those fences could be trusted anyway, the trade was easy.

3. The decision, the repair, and the cost that’s left over

Host: So walk me through what actually landed in the repo. Not the philosophy anymore, the mechanics — what’s the diff look like?

Guest: One line in .prettierignore, apps/handbook/src/content/docs plus the glob for MDX, so the whole docs tree is hands-off for Prettier going forward. The six corrupted pages got hand-repaired, and then verified by literally parsing every fenced Python block with Python’s own ast.parse — not the linter, not Prettier, the actual language parser, which is strong enough to catch this exact failure mode, one that neither Prettier nor the existing content linter would. Module 5, Agent Engineering, and Module 7, LangGraph, are two of those six, and they’re the ones I’d point anyone to if they want to see real corrupted-then-restored examples rather than a synthetic case. The catch is what we lose: pnpm format:check no longer touches prose or JSX in those files, so sloppy spacing or wrapping in docs just won’t get flagged anymore, that’s a permanent, accepted cost. And it means every future code example dropped into a CodeWalkthrough is on the author to verify by hand, because a clean pnpm verify literally does not mean the code inside those fences is valid — nothing in CI parses Markdown fences today. Even this ADR says so itself: if Prettier ever ships a fix and someone’s tempted to re-enable it, the obligation is to re-run the same ast.parse check against real content first, not just trust a changelog entry.

Host: Which is really the whole shape of this decision in one sentence — trade a small, visible, cosmetic cost for removing a silent, invisible, correctness-breaking one. That’s ADR-0006. Thanks for walking through it.

Not covered

The planner wanted these and found nothing in the source to support them:

  • What the corrupted Module 5 and Module 7 code examples actually taught about agent loops or LangGraph (the ADR only references these pages as evidence of the bug, not their content)
  • Any detail of the agent loop, tool-calling, or LangGraph checkpointing material itself, since it’s unrelated to the Prettier decision beyond being the corrupted content

Generated from this page by Claude Sonnet 5 on , spoken by Kokoro-82M running locally. Two synthetic voices, not a recorded conversation. Every claim is drawn from this page — where it differs from the text above, the text is correct.

ADR-0006acceptedAugust 5, 2026

Accepted. Implemented by adding apps/handbook/src/content/docs/**/*.mdx to .prettierignore, and by repairing six already-corrupted module pages.

Six Learn module pages (Modules 1, 2, 4, 5, 6, and 7) contain Python code examples inside <CodeWalkthrough> components — a fenced code block as a child of a custom JSX/MDX component, rather than at the top level of the document. Running pnpm format (Prettier, --write) across the repository silently rewrote several of these blocks: indentation was stripped from statements following a blank line inside the fence, comments got merged onto the preceding code line, and underscores/asterisks in identifiers (__init__, self._admit) were backslash-escaped as if they were Markdown emphasis syntax. The result was Python that no longer parsed, shipped past pnpm format and pnpm build because neither checks that a fenced code block’s contents are valid code in their declared language — only scripts/lint-content-structure.ts’s required-heading check and Astro’s frontmatter schema ran against these pages, and neither would have caught this.

Prettier’s MDX/remark-based formatter treats a fenced code block nested inside a custom JSX component’s children differently from one at a document’s top level, and — specifically once a blank line appears inside that nested fence — drifts from treating the block as an opaque code fence into treating some of its lines as Markdown prose (applying Markdown escaping rules to underscores and asterisks, and losing the leading whitespace a prose paragraph would ordinarily be reflowed without). A minimal reproduction confirmed this: an identical code fence with a blank line inside it was left untouched at the top level of an .mdx file, but corrupted when the same fence was made a child of a JSX component. How do we keep the reliability Prettier gives the rest of the codebase without exposing content authors to a formatter that can silently break their code examples?

  • Never put a blank line inside a nested fenced code block. Technically avoids the trigger, but makes it a landmine for every future contributor who doesn’t know the rule, with no lint rule enforcing it and a failure mode (corrupted, unparseable code, not a formatting diff) severe enough that “just don’t do the thing” isn’t an adequate mitigation on its own.
  • Stop wrapping code examples in <CodeWalkthrough> and other components, keeping every fence at the document’s top level. This works around the bug but gives up the narrative framing CodeWalkthrough and similar components provide, for every future code example in the handbook, not just the ones already affected.
  • Exclude apps/handbook/src/content/docs/**/*.mdx from Prettier entirely. Content pages lose automatic prose/JSX formatting, but authors already control formatting inside fenced code blocks by hand (they’re excerpts from real source or illustrative examples, not generated), so the practical loss is address only cosmetic JSX/Markdown formatting outside of code fences — nothing Prettier does inside a .mdx file’s code fences today can be trusted anyway.

Exclude every file under apps/handbook/src/content/docs/ from Prettier via .prettierignore. Content authors are responsible for their own formatting in .mdx files; pnpm lint:content and Astro’s build-time frontmatter schema remain the automated checks for these pages. The six affected pages were repaired by hand and verified by parsing every fenced Python block with Python’s own ast.parse() — a check strong enough to catch this exact failure mode, which neither Prettier nor the existing content linter would.

  • Content .mdx files no longer get automatic formatting — inconsistent spacing or line-wrapping in prose or JSX won’t be caught by pnpm format:check. This is a real, accepted cost, traded against a bug that silently breaks code correctness rather than just cosmetics.
  • Every future code example nested inside a doc component (CodeWalkthrough or otherwise) needs to be verified by the author, not assumed safe because pnpm format ran clean — pnpm verify passing does not mean a fenced code block’s contents are syntactically valid, since nothing in this repository’s CI actually parses code inside Markdown/MDX fences today.
  • This ADR is itself evidence for the fix: if Prettier is ever re-enabled for content pages (a newer version fixing the underlying bug, for instance), re-verify with the same ast.parse()-per-block check before trusting it, rather than assuming a version bump alone fixed it.