Skip to content

chore: hard-wrap markdown at 80 cols via prettier + pre-commit - #75

Merged
edochi merged 4 commits into
mainfrom
chore/markdown-formatting
Aug 20, 2026
Merged

chore: hard-wrap markdown at 80 cols via prettier + pre-commit#75
edochi merged 4 commits into
mainfrom
chore/markdown-formatting

Conversation

@edochi

@edochi edochi commented Aug 20, 2026

Copy link
Copy Markdown
Owner

Flips the repo's markdown convention from "no hard-wrap" to a hard 80-column wrap, enforced by prettier via a pre-commit hook and a CI check.

MD013 was firing on essentially every markdown file in editors. MD013 has no auto-fix, so the choice was to disable the rule or adopt wrapping; this PR adopts wrapping.

Tooling

File Role
.prettierrc.yaml proseWrap: always, printWidth: 80, embeddedLanguageFormatting: off
.prettierignore fixtures, corpora, generated CHANGELOG.md, target/
.markdownlint-cli2.yaml MD013 at 80 with code_blocks / tables / headings off
.pre-commit-config.yaml local prettier@3.6.2 hook, language: node
Justfile just fmt-md / just check-md
ci.yml fmt-md job running prettier --check

Setup is uv tool install pre-commit && pre-commit install. uv tool, not uvxpre-commit install bakes the interpreter path into .git/hooks/pre-commit, and a uvx cache entry can be pruned out from under it. Node and prettier are provisioned by pre-commit; nothing needs a global npm install.

Tables, fenced code blocks, headings and long URLs are deliberately left over-length. MD013 disables those three checks and is non-strict for lines with no space past the limit, so the two tools agree on what "formatted" means.

embeddedLanguageFormatting: off stops prettier rewriting the contents of fences whose language it can parse (json, yaml, js) — otherwise doc examples get silently reformatted.

Fixtures and corpora are excluded from both tools because their exact frontmatter bytes are under test: prettier rewrites YAML frontmatter (quote style, indentation, flow-sequence spacing) and doesn't recognise TOML +++ or bare-brace JSON frontmatter at all.

Verification

Every file was rendered before and after through CommonMark + GFM tables, with the HTML whitespace-normalised and compared. 276 files reformatted, zero unintended rendering changes. Prettier is idempotent across the repo, mdbook build passes, no fixture or non-markdown file was touched, and MD013 violations went from ~3,400 to 0.

Five files hand-fixed first

Two root causes, both of which silently change rendered output:

Bare snake_case identifiers pairing as emphasis across a code span. In TODO-0184, prettier turned write_index into write*index and ate the spaces around three adjacent code spans:

- **Pipeline-behavior** (classify, write_index decisions, search
  result count, error handling, `auto_*` chains) → switch
- **Pipeline-behavior** (classify, write*index decisions, search result count,
  error handling, `auto*\*`chains) → switch`EmbeddingModelConfig`to`provider:

TODO-0106 and TODO-0162 were worse: the first pass rewrote *every* to _every_, and that new underscore then paired with a bare one earlier in the paragraph on the second pass. Formatted, committed, clean — and corrupting on next touch. The pre-commit hook cannot detect this, because it only ever sees the file it just rewrote. This is what the CI job is for.

Unescaped pipes inside code spans in table cells. | `"value {value} {< | >} {limit}"` | was already splitting cells; after reformatting the whole table degraded to a paragraph of literal pipes. Fixed with \|.

TODO-0155 also moves from a tight to a loose list — prettier always inserts a blank line before a fence inside a list item, so the blank lines are now explicit rather than surfacing in some later unrelated diff.

Commits

  • e5cf18b — configs, hook, AGENTS.md rule
  • 8a15864 — just recipes, CI job, trimmed comments
  • 46a3cb7 — the reformat (273 files)

The reformat is mechanical and kept in its own commit; review the first two and skim the third.

Note

Prettier 3.6.2 is pinned in three places (.pre-commit-config.yaml, Justfile, ci.yml). Bump all three together — the alternative is CI and local disagreeing about what "formatted" means.

edochi added 4 commits August 20, 2026 19:26
Add prettier (proseWrap: always, printWidth: 80) wired through a local
pre-commit hook, and tune markdownlint's MD013 to match so the two agree.

Tables, fenced code blocks, headings and long URLs are left over-length by
design — MD013 disables those three checks and is non-strict for unbreakable
lines. embeddedLanguageFormatting is off so prettier never rewrites the
contents of a fence.

Corpora and fixtures are excluded from both tools: prettier rewrites YAML
frontmatter and does not recognise TOML (+++) or bare-brace JSON frontmatter,
which would mangle example_kb, assets/demo_kb and the multi-format test
fixtures. The generated CHANGELOG.md is excluded to avoid fighting cog.

AGENTS.md is reformatted by the new hook; the rest of the tree is left for a
separate bulk pass.
`just fmt-md` / `just check-md` mirror the pre-commit hook for manual runs.
The CI job re-checks committed content, which the hook cannot do — the hook
only ever sees the file it just rewrote, so it can't detect a formatting
fixed-point being lost.

Prettier is pinned to 3.6.2 in .pre-commit-config.yaml, the Justfile and
ci.yml; bump all three together.

Config comments trimmed to the non-obvious why.
Mechanical prettier pass over every tracked .md outside .prettierignore.
Verified by rendering each file before and after through CommonMark + GFM
tables and comparing normalised HTML: 276 files reformatted, zero unintended
rendering changes.

Five files needed hand-fixing first, from two root causes:

- Bare snake_case identifiers in prose pairing as emphasis across a code span.
  Prettier rewrote `write_index` to `write*index` and ate the spaces around
  adjacent code spans (TODO-0184), and in TODO-0106 / TODO-0162 the first pass
  emitted output that a second pass corrupted — a lost fixed point the hook
  cannot detect. Fixed by code-spanning the identifiers.
- Unescaped pipes inside code spans in table cells, which degraded a table to
  a paragraph of literal pipes (TODO-0149). Fixed with `\|`.

TODO-0155 additionally goes from a tight to a loose list: prettier always
inserts a blank line before a fence inside a list item, so the blank lines are
now explicit rather than appearing in a later diff.
…ting

# Conflicts:
#	docs/spec/todos/TODO-0196.md
#	docs/spec/todos/index.md
@edochi
edochi merged commit 8f640ee into main Aug 20, 2026
9 checks passed
@edochi
edochi deleted the chore/markdown-formatting branch August 20, 2026 21:10
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant