Nested markdown lists: first item of a 3rd-level list is indented 2 spaces too deep
Environment
- Claude Code 2.1.220 (native install)
- macOS (Darwin 25.5.0), node v20.19.6
What happens
When assistant output contains a markdown list nested 3 levels deep, the first item of
the deepest list is rendered 2 spaces deeper than its siblings.
Source (assistant message text):
- L1
- L2
- item A
- item B
Rendered in the terminal:
- L1
- L2
- item A <- 6 spaces
- item B <- 4 spaces
Expected: item A and item B share the same indentation.
Two-level lists render correctly.
Cause
In the markdown-to-terminal renderer, list_item stringifies each child token and
prefixes the parent indent to that whole string. A nested list is a multi-line string,
so the parent indent lands on its first line only:
case "list_item": return (e.tokens ?? []).map((child) => {
const d = render(child, { listDepth: n + 1, ... });
return `${" ".repeat(n)}${d}`; // applied to the entire multi-line string
}).join("")
Two-level lists are unaffected because the parent's n is 0.
Repro (extracted logic, plain node)
const NL = "\n";
function render(tok, n = 0, parent = null) {
switch (tok.type) {
case "list": return tok.items.map((it) => render(it, n, tok)).join("");
case "list_item": return (tok.tokens || []).map((child) => " ".repeat(n) + render(child, n + 1, tok)).join("");
case "text": return parent && parent.type === "list_item" ? `- ${tok.text}${NL}` : tok.text;
}
}
const row = (t) => ({ type: "list_item", tokens: [{ type: "text", text: t }] });
const nest = (label, inner) => ({ type: "list_item", tokens: [{ type: "text", text: label }, inner] });
const three = { type: "list", items: [nest("L1", { type: "list", items: [nest("L2", { type: "list", items: [row("item A"), row("item B")] })] })] };
console.log(render(three));
// => item A gets 6 spaces, item B gets 4
Non-workarounds
Changing the source indent width (2 / 4 / 6 spaces, tabs), changing the bullet marker,
inserting blank lines between items, and reordering items all fail — the displayed
indent is generated from listDepth, not from the source whitespace.
This issue has 2 comments on GitHub. Read the full discussion on GitHub ↗