Repository navigation
Replace markdownlint-cli2 with rumdl for Markdown linting (GH-1352) - #1360
laughingman7743 wants to merge 3 commits into
Conversation
markdownlint-cli2 ran through mise's npm backend, which needs a Node.js
runtime that .mise.toml never declared. rumdl is a single binary in the
mise registry, so `mise install` and `just docs lint` no longer depend on
a global Node.js.
The rule settings and globs carry over from .markdownlint-cli2.jsonc into
.rumdl.toml. docs/ uses the MyST flavor so directive fences such as
```{toctree} are not reported as code blocks without a language.
Closes #1352
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
|
||
| _docs-format: | ||
| mise exec -- markdownlint-cli2 --fix | ||
| mise exec -- rumdl check --fix |
There was a problem hiding this comment.
Self-review round one — implementation behavior: CLEAN
Base d2c63f61bf19660395860056cd3f537261fbc698, head 07f826c9c140da4ce484ea16f30fb75a97244d70.
Covered: .mise.toml, justfile recipes, .rumdl.toml (rules, include globs, MyST per-file flavor), removed .markdownlint-cli2.jsonc, docs-lint.yaml path filter, AGENTS.md, development-workflow skill.
Checks:
just docs formatfailure path: on a seeded file with one fixable (MD040) and one unfixable (MD033) issue,rumdl check --fixfixes the first and exits 1, so the recipe still fails likemarkdownlint-cli2 --fixwhen issues remain.MD007style = "fixed": a-sublist indented 3 spaces under an ordered item is not reported, matching markdownlint (which appliesMD007only to bullets nested in bullets).- File set and excluded build output: 26 files,
docs/_buildand the other oldignoresare gitignored and rumdl respects.gitignore. .rumdl_cache/is created in the checkout but carries its own.gitignore, so it never shows as untracked.
Behavior difference recorded in the PR body: rumdl check --fix adds text to fences without a language (MD040), which markdownlint-cli2 does not auto-fix; repository files have none, so just docs format makes no change.
No tests are added: the change is tool configuration with no Python behavior; the Docs Lint workflow is the check.
| "MD014", | ||
| # MyST `(label)=` ref targets must come before the first heading, so the | ||
| # first line of many docs/*.md files is not an H1 | ||
| "MD041", |
There was a problem hiding this comment.
Self-review round two — claims and operational behavior: FINDINGS (fixed in the PR body)
Base d2c63f61bf19660395860056cd3f537261fbc698, head 07f826c9c140da4ce484ea16f30fb75a97244d70.
Claims checked:
rumdlis in the mise registry asaqua:rvben/rumdl:mise registry rumdl→aqua:rvben/rumdl github:rvben/rumdl.- The project no longer needs Node.js: no
package.json,.nvmrc, or other npm/Node reference remains in tracked files (git grep); a run with nonodeonPATHpassesmise exec -- rumdl check. - Unanchored
*.mdmatches every directory: with"*.md"rumdl lints 39 files including.github/and.agents/; with"/*.md"it lints 26. - Old
ignoresare covered by.gitignore(git check-ignorefordocs/_build,.venv,.tox,.pytest_cache,.serena);node_modulesdoes not match any include glob. docs-lint.yamlruns on this PR: the Docs Lintlintjob passed on this head.AGENTS.md/ skill: the documented commands (mise install,just docs lint,just docs format,mise exec -- rumdl check .agents/skills) were run and succeed. No other doc names markdownlint (git grep -i markdownlintis empty apart from the removed config).
Finding (fixed): the PR body said MD041 is still reported in 19 files. That count came from the unanchored config, which included 3 .github/ templates. With the final config it is 16, all docs/ pages whose first content is a (label)= target. The PR body now says so and also records that rumdl check --fix auto-fixes MD040, which round one referred to.
rumdl enables rules beyond markdownlint 0.38 (such as MD064) and some shared rules have different defaults (MD051 ignore-case, MD010 code-blocks), so files markdownlint accepted could fail and some violations it reported could pass. Enable exactly the markdownlint 0.38 rules and set the differing options to markdownlint's defaults. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
| "cloudformation/**/*.md", | ||
| "/*.md", | ||
| ] | ||
| disable = [ |
There was a problem hiding this comment.
Independent review (relayed): FINDINGS
Reviewer: Codex CLI 0.166.0 (codex exec -s read-only, model gpt-6-astra, session 01a1abd1-3db0-7df0-b0f8-f1284ae7859c). Static review of a detached snapshot at the head. It was given the diff and the intended behavior only, without the PR text, commit messages, or self-review records, and was not permitted to edit, build, run tests, or access GitHub; it ran read-only rumdl check probes.
Base d2c63f61bf19660395860056cd3f537261fbc698, head 07f826c9c140da4ce484ea16f30fb75a97244d70.
Covered: exact diff and merge-base config; file selection, anchoring, ignores and symlinks; MyST flavor; MD007/MD024/MD033 and inherited defaults; recipe exit behavior; mise/CI wiring and path filters; tracked docs/skills references.
- P2: shared-rule defaults are not preserved (
.rumdl.toml:20). Options left unset inherit rumdl's defaults.## Basic usagefollowed by[Usage](#Basic-usage)now passes because MD051 matches case-insensitively, while markdownlint rejected it. MD010 also stops checking tabs inside code blocks. Restore the previous options, includingMD051.ignore-case = falseandMD010.code-blocks = true. - P2: additional rules introduce new lint failures (
.rumdl.toml:20). Disabling only MD013/MD014/MD041 leaves rumdl-only rules enabled, including MD057 and MD064.One sentence. Another sentence.passed before and now exits 1 with MD064. Select the previous rule set explicitly or disable the additional rules.
Non-actionable notes: 26 selected files and the four agent skills pass; root anchoring and the benchmark depth restriction work; CLAUDE.md (a symlink) is skipped while its target AGENTS.md is checked; MD007/MD024/MD033 behave as intended; both recipes propagate failures; CI wiring and path filters are consistent; no tracked references to the old tool remain.
Author verification: both findings reproduced. rumdl config shows MD051.ignore-case = true and MD010.code-blocks = false by default, and rumdl defines rules MD057 and MD060–MD095 that markdownlint 0.38 lacks.
There was a problem hiding this comment.
Repair: a9ec6a3 (base d2c63f61bf19660395860056cd3f537261fbc698, head a9ec6a35)
- Finding 2:
global.enablenow lists exactly the rules of markdownlint 0.38.0, the version markdownlint-cli2 0.18.1 runs, minus MD013/MD014/MD041. Thedisablelist is gone, and the reasons for the three omissions are kept as comments. Checked with a script against the rule keys of the installedmarkdownlint@0.38.0config schema: missing = MD013/MD014/MD041, extra = none. - Finding 1: every rumdl default for those rules was compared with the schema defaults, and each one that differs is now set to markdownlint's value:
MD010(code-blocks = true,spaces-per-tab = 1),MD026/MD036(CJK punctuation),MD027(list-items = true),MD051(ignore-case = false),MD052(ignore = ["x"]),MD053(ignored-definitions = ["//"]).MD044code-blocksis left alone because no names are configured. - Validation: a probe file with a case-mismatched fragment, a tab in a code block, an unused definition, a sentence double space, and a lazy list continuation gets the same results from both tools (MD051, MD010, MD053; nothing for the last two).
just docs lint,just docs format(no diff),rumdl check .agents/skills, andjust lintpass.
Self-review of the repair. Round one (behavior): the enable list is an allowlist; rumdl config shows it loaded from .rumdl.toml with an empty disable. Round two (claims): the comment saying markdownlint 0.38 is what cli2 0.18.1 runs is taken from the installed package's package.json; the PR body now describes the rule set and the option alignment. An independent follow-up on this repair comes next.
markdownlint's MD001 checks only body headings, while rumdl counts a front matter title as a level-1 heading by default. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
| [MD033] | ||
| allowed-elements = ["details", "summary", "br", "kbd", "sub", "sup", "div", "img", "p", "a"] | ||
|
|
||
| # Options whose rumdl defaults differ from markdownlint's |
There was a problem hiding this comment.
Independent follow-up review (relayed): FINDINGS
Reviewer: Codex CLI 0.166.0 (codex exec -s read-only, model gpt-6-astra, session 01a1abd9-5fc4-7781-b81c-47a83008f2e4). Static review with read-only rumdl check probes; given the repair diff 07f826c9..a9ec6a35 and the earlier findings, without the PR text or self-review records; no edits, builds, tests, or GitHub access.
Base d2c63f61bf19660395860056cd3f537261fbc698, head a9ec6a35b4ff886e90a9b55c7c2f8c24220fe07e.
Covered: repair diff, previous configuration, installed markdownlint 0.38 source/schema, rumdl 0.3.2 effective configuration, file selection, MyST settings, comments. rumdl check --no-cache --deny-config-warnings passes all 26 files.
Result: the allowlist finding is resolved. enable selects exactly the 49 expected rules, and all eight added option assignments are valid and match markdownlint's defaults (including ignored_labels → ignore).
- P2: MD001's differing default remains unset (
.rumdl.toml:58). rumdl defaultsfront-matter-titletotrue; markdownlint 0.38's MD001 considers only body headings. Front mattertitle: Examplefollowed by### First sectiongains an MD001 failure.[MD001] front-matter-title = falseremoves it. - P3: MD025 default title matching is not equivalent (
.rumdl.toml:58). markdownlint's default matcher recognizes quoted and case-varied title keys; rumdl 0.3.2 does not report MD025 for"title": ExampleorTitle: Examplefollowed by# Main heading. Copying markdownlint's regex into rumdl'sfront-matter-titledid not restore detection.
Notes: MD044 code-blocks differs, but names = [] makes it inactive. File selection and MyST settings are unchanged by the repair.
There was a problem hiding this comment.
Repair: dfbab73
- Finding 1 (fixed): reproduced with a probe (front matter
title: Example+### First section): rumdl reported MD001 and markdownlint-cli2 0.18.1 did not. Added[MD001] front-matter-title = false, after which rumdl reports nothing.just docs lint,just docs format(no diff), andjust lintpass. - Finding 2 (deferred, documented): rumdl 0.3.2 has no option that reproduces markdownlint's MD025 title-key pattern (the reviewer found that copying the regex does not work). The difference only affects front matter with quoted or capitalized
titlekeys, and none of the 26 linted files has front matter (checked the first line of each). The PR body now lists it as a known remaining difference instead of claiming full parity.
Self-review of the repair. Behavior: a one-option change to a rule that is already enabled; the file set and other rules are untouched. Claims: the PR body now names MD001 among the aligned options and states the MD025 limitation.
| enable = [ | ||
| "MD001", "MD003", "MD004", "MD005", "MD007", "MD009", "MD010", "MD011", | ||
| "MD012", "MD018", "MD019", "MD020", "MD021", "MD022", "MD023", "MD024", | ||
| "MD025", "MD026", "MD027", "MD028", "MD029", "MD030", "MD031", "MD032", |
There was a problem hiding this comment.
Independent follow-up review 2 (relayed): FINDINGS (deferred, documented)
Reviewer: Codex CLI 0.166.0 (codex exec -s read-only, model gpt-6-astra, session 01a1abe5-152c-79f3-b80e-72061eaa38c1). Static review with read-only, cache-disabled rumdl check probes; given the repair diff a9ec6a35..dfbab738; no edits, builds, tests, or GitHub access.
Base d2c63f61bf19660395860056cd3f537261fbc698, head dfbab738.
Covered: base-to-head and repair diffs; all 49 enabled-rule defaults against the local markdownlint 0.38 sources; the effective rumdl configuration; the default and skill lint scopes (26 + 4 files pass).
- MD001 repair verified: front matter titles no longer affect the first body heading, and body heading-level skips are still detected. No side effects.
- Front matter deferral judged reasonable: none of the 26 default files has front matter. The four skill files have front matter with only
name/descriptionkeys. - P2: MD025 differs for documents without front matter (
.rumdl.toml:25). WithPreamble.followed by# Section oneand# Section two, markdownlint 0.38 does not report MD025 because prose precedes the first H1, while rumdl reports line 5, also under the MyST flavor.allow-document-sections = truedoes not resolve it. - No other result-changing default mismatch was found. MD044
code-blocksdiffers but is inactive with emptynames.
Author disposition: reproduced; allow-document-sections and allow-with-separators both still report it. Deferred: rumdl 0.3.2 has no option for this, rumdl is the stricter side, and no linted file triggers it. The PR body now lists it under the known remaining MD025 differences. No code change, so dfbab738 remains the reviewed head.
WHAT
Replace
markdownlint-cli2with rumdl forjust docs lint/just docs format..mise.toml:"npm:markdownlint-cli2" = "0.18.1"→rumdl = "0.3.2"(mise registry,aqua:rvben/rumdl).justfile:_docs-lint→mise exec -- rumdl check,_docs-format→mise exec -- rumdl check --fix..rumdl.tomlreplaces.markdownlint-cli2.jsonc(removed). It started fromrumdl import .markdownlint-cli2.jsoncand keeps the same rule settings and comments:MD013,MD014,MD041off,MD004dash,MD007indent 2 (fixed),MD024siblings only,MD033allowed elements.enablelists exactly its rules minus the three disabled ones, so rumdl-only rules such asMD057orMD064do not run. Options whose rumdl defaults differ from markdownlint's are set to markdownlint's values (MD001body headings only,MD010code blocks and tab width,MD026/MD036CJK punctuation,MD027list items,MD051case-sensitive fragments,MD052ignoredxlabel,MD053ignored//definitions).MD044code-blocksis left at rumdl's default because no names are configured.MD025differences that rumdl 0.3.2 options cannot remove:"title":,Title:), while rumdl recognizes onlytitle:. None of the linted files has front matter.MD025when prose precedes the first H1, while rumdl reports a second H1 in that case too (allow-document-sectionsandallow-with-separatorsdo not change this). rumdl is stricter here, and no linted file currently triggers it.includecarries over the globs; the root glob is written/*.mdbecause rumdl matches an unanchored*.mdin every directory. The oldignoresare dropped: rumdl respects.gitignore, which already coversdocs/_build,.venv,.tox,.pytest_cache, and.serena, and none of them match the include globs anyway.docs/**/*.mduses the MyST flavor, so MyST directive fences such as```{toctree}are not reported byMD040..github/workflows/docs-lint.yaml: thepathstrigger watches.rumdl.tomlinstead of.markdownlint-cli2.jsonc.AGENTS.mdand thedevelopment-workflowskill name the new tool, config file, and command.MD041stays disabled: with the MyST flavor, rumdl still reports it for all 16docs/pages whose first content (after the license comment) is a(label)=target.WHY
Closes #1352.
mise's npm backend needs Node.js, which
.mise.tomlnever declared, so Markdown linting silently relied on a global Node.js (present onubuntu-latest, but not necessarily for contributors).rumdl is a single binary, so the project no longer needs Node.js for anything.
TEST
Tested commit: dfbab73.
mastercomparison:markdownlint-cli2reports 0 errors in 27 files.rumdl check .with only the imported config reports 11MD040findings, all MyST directive fences ({toctree},{note}) indocs/; the MyST flavor resolves them.markdownlint-cli2minusCLAUDE.md, a symlink toAGENTS.md.MD004,MD007,MD033,MD024siblings,MD040,MD003, MyST fence,$ ls): both tools report the same configured rules. Differences: rumdl does not reportMD032when a list switches from*to-markers without a blank line (markdownlint treats them as two lists), and it additionally reportsMD025for a second setext H1.enablelist equals the rule keys of the installed markdownlint 0.38.0 config schema minusMD013/MD014/MD041. Option defaults were compared against that schema's defaults. A probe with a case-mismatched fragment link, a tab inside a code block, an unused reference definition, a double space between sentences, and a lazy list continuation gets the same results from both tools (MD051,MD010,MD053; nothing for the last two).just docs formatbehavior: on a file with one fixable and one unfixable issue,rumdl check --fixfixes the first and exits 1, asmarkdownlint-cli2 --fixdoes. Unlike markdownlint-cli2, it also auto-fixesMD040by addingtextto a fence without a language.just docs lint: no issues in 26 files.just docs format: no diff.env -ishell with nonodeonPATH:mise exec -- rumdl checkpasses.mise exec -- rumdl check .agents/skills: no issues in 4 files.just lint: passes.Docs Lintworkflow runs on this PR because.mise.toml,justfile, and**.mdchanged.🤖 Generated with Claude Code