chore: add markdownlint and fix violations across all markdown files - #1349
chore: add markdownlint and fix violations across all markdown files#1349snimu wants to merge 5 commits into
Conversation
Adds markdownlint-cli2 with the same rule baseline as research-environments/verifiers (MD013 off, MD024 siblings-only, MD041 off, MD060 compact tables, inline-HTML allowlist for README branding). Wired into 'npm run check' as 'check:md' (~0.6s), so the existing pre-commit hook and CI enforce it without workflow changes. File changes are almost entirely mechanical (--fix): blank lines around headings/lists/fences, table pipe spacing, bare URLs wrapped. Manual: language tags on 37 unlabeled code fences, a broken anchor in docs/rpc.md, two duplicate '### Added' siblings merged in packages/ai/CHANGELOG. No prose changes.
The unmatched fence before '## Limitations' made everything below it render as a code block (pre-existing; the MD040 pass had labeled it bash instead of noticing it was unmatched). Removing it exposed two mechanical blanks-around violations below, fixed with --fix. Also dedupes the accidental double 'check:md' invocation in npm run check.
…ing docs One logical line per paragraph/bullet: hard wraps distort line counts and make one-word edits touch whole paragraphs in diffs. Custom rule in scripts/markdownlint/no-hard-wraps.cjs (skips code fences, HTML blocks, tables, headings, blockquotes, reference definitions, and deliberate trailing-double-space/backslash breaks). 372 wrapped continuation lines joined across 22 files; word-level diff is whitespace-only.
| lineNumber: i + 2, | ||
| detail: "Continuation of the previous line; keep one logical line per paragraph/bullet.", | ||
| }); | ||
| } |
There was a problem hiding this comment.
Wrap rule flags YAML and fences
High Severity
PA001 treats YAML frontmatter keys as wrappable prose and closes an outer fence when it sees a shorter inner fence of the same character. That produced the collapsed frontmatter and joined nested samples, and it will still fail check:md on remaining valid files such as prime-intellect/SKILL.md and planner.md.
Reviewed by Cursor Bugbot for commit 173e387. Configure here.
| let inFence = false; | ||
| let fenceMarker = ""; | ||
| for (let i = 0; i < lines.length - 1; i++) { | ||
| const line = lines[i]; | ||
| const fence = line.match(/^\s*(`{3,}|~{3,})/); | ||
| if (fence) { | ||
| if (!inFence) { | ||
| inFence = true; | ||
| fenceMarker = fence[1][0]; | ||
| } else if (fence[1][0] === fenceMarker) { | ||
| inFence = false; | ||
| } |
There was a problem hiding this comment.
🟡 Medium markdownlint/no-hard-wraps.cjs:24
The linter closes a four-backtick fenced block with a later three-backtick line, and it also closes a block on an in-fence line such as ```javascript; the remaining code is then scanned as prose and can produce false PA001 errors. The closing check must require the same fence character, a length at least as long as the opener, and only whitespace after the fence.
let inFence = false;
let fenceMarker = "";
+ let fenceLength = 0;
for (let i = 0; i < lines.length - 1; i++) {
const line = lines[i];
- const fence = line.match(/^\s*(`{3,}|~{3,})/);
+ const fence = line.match(/^\s*(`{3,}|~{3,})(.*)$/);
if (fence) {
if (!inFence) {
inFence = true;
fenceMarker = fence[1][0];
- } else if (fence[1][0] === fenceMarker) {
+ fenceLength = fence[1].length;
+ } else if (
+ fence[1][0] === fenceMarker &&
+ fence[1].length >= fenceLength &&
+ /^\s*$/.test(fence[2])
+ ) {
inFence = false;
}🚀 Reply "fix it for me" or copy this AI Prompt for your agent:
In file @scripts/markdownlint/no-hard-wraps.cjs around lines 24-35:
The linter closes a four-backtick fenced block with a later three-backtick line, and it also closes a block on an in-fence line such as [code fence]javascript; the remaining code is then scanned as prose and can produce false `PA001` errors. The closing check must require the same fence character, a length at least as long as the opener, and only whitespace after the fence.
Evidence trail:
scripts/markdownlint/no-hard-wraps.cjs:24-38 (REVIEWED_COMMIT); https://spec.commonmark.org/0.28/#fenced-code-blocks
| termux-open file.pdf # Opens with default app termux-open -c image.jpg # Choose app | ||
| ``` | ||
|
|
||
| ## Clipboard | ||
|
|
||
| ```bash | ||
| termux-clipboard-set "text" # Copy | ||
| termux-clipboard-get # Paste | ||
| termux-clipboard-set "text" # Copy termux-clipboard-get # Paste | ||
| ``` | ||
|
|
||
| ## Notifications | ||
|
|
||
| ```bash | ||
| termux-notification -t "Title" -c "Content" | ||
| ``` | ||
|
|
||
| ## Device Info | ||
|
|
||
| ```bash | ||
| termux-battery-status # Battery info | ||
| termux-wifi-connectioninfo # WiFi info | ||
| termux-telephony-deviceinfo # Device info | ||
| termux-battery-status # Battery info termux-wifi-connectioninfo # WiFi info termux-telephony-deviceinfo # Device info | ||
| ``` | ||
|
|
||
| ## Sharing | ||
|
|
||
| ```bash | ||
| termux-share -a send file.txt # Share file | ||
| ``` | ||
|
|
||
| ## Other Useful Commands | ||
|
|
||
| ```bash | ||
| termux-toast "message" # Quick toast popup | ||
| termux-vibrate # Vibrate device | ||
| termux-tts-speak "hello" # Text to speech | ||
| termux-camera-photo out.jpg # Take photo | ||
| termux-toast "message" # Quick toast popup termux-vibrate # Vibrate device termux-tts-speak "hello" # Text to speech termux-camera-photo out.jpg # Take photo |
There was a problem hiding this comment.
🟡 Medium docs/termux.md:55
The Opening Files, Clipboard, Device Info, and Other Useful Commands examples execute only their first command when copied into a shell, so users cannot perform the documented operations. The commands were collapsed into lines where # comments out everything after the first command; restore each command to its own line.
-termux-open file.pdf # Opens with default app termux-open -c image.jpg # Choose app
+termux-open file.pdf # Opens with default app
+termux-open -c image.jpg # Choose app
-termux-clipboard-set "text" # Copy termux-clipboard-get # Paste
+termux-clipboard-set "text" # Copy
+termux-clipboard-get # Paste
-termux-battery-status # Battery info termux-wifi-connectioninfo # WiFi info termux-telephony-deviceinfo # Device info
+termux-battery-status # Battery info
+termux-wifi-connectioninfo # WiFi info
+termux-telephony-deviceinfo # Device info
-termux-toast "message" # Quick toast popup termux-vibrate # Vibrate device termux-tts-speak "hello" # Text to speech termux-camera-photo out.jpg # Take photo
+termux-toast "message" # Quick toast popup
+termux-vibrate # Vibrate device
+termux-tts-speak "hello" # Text to speech
+termux-camera-photo out.jpg # Take photoAlso found in 1 other location(s)
packages/coding-agent/docs/skills.md:377
The two documented Brave Search invocations were collapsed onto one shell line:
./search.js "query" --contentis now part of the comment after#. Copying the documented command therefore only runs the basic search and never enables the advertised--contentoption, so users cannot follow the example to retrieve page content.
🚀 Reply "fix it for me" or copy this AI Prompt for your agent:
In file @packages/coding-agent/docs/termux.md around lines 55-85:
The `Opening Files`, `Clipboard`, `Device Info`, and `Other Useful Commands` examples execute only their first command when copied into a shell, so users cannot perform the documented operations. The commands were collapsed into lines where `#` comments out everything after the first command; restore each command to its own line.
Evidence trail:
packages/coding-agent/docs/termux.md:52-85 at 173e387f68
Also found in 1 other location(s):
- packages/coding-agent/docs/skills.md:377 -- The two documented Brave Search invocations were collapsed onto one shell line: `./search.js "query" --content` is now part of the comment after `#`. Copying the documented command therefore only runs the basic search and never enables the advertised `--content` option, so users cannot follow the example to retrieve page content.
jonaowen
left a comment
There was a problem hiding this comment.
The mechanical unwrap changed significant literal bytes inside inline code spans, contradicting the “no prose changes” claim.
Examples on exact head 173e387f6:
packages/ai/CHANGELOG.md0.2.2 previously documented dropping the suffix` (Prime Inference)`(including the leading space). The rewrite now says`(Prime Inference)`, which is a different suffix.packages/coding-agent/CHANGELOG.mdpreviously documented connectors`├ `/`└ `and replacements`├─ `/`└─ `with significant trailing spaces. The rewrite removes every trailing space and now documents different strings.
These are user-facing historical/behavioral claims, not style. A formatter/lint rule must preserve whitespace inside code spans and other literal regions. Restore the exact literals and add focused regression fixtures for inline code with leading/trailing spaces (including spans split by historical hard wraps) before applying this rule repo-wide. Please also audit all 67 changed Markdown files for the same class; a green Markdown lint cannot detect semantic byte loss it caused.
|
Additional binding evidence from the PR's own required CI: |
|
Fresh independent review found three further semantic classes on the same head:
The corrupted subagent reviewer frontmatter also collapses |
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 1 potential issue.
There are 2 total unresolved issues (including 1 from previous review).
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit 95b8a1c. Configure here.
| description: Code review specialist for quality and security analysis | ||
| tools: bash | ||
| model: claude-sonnet-4-5 | ||
| name: reviewer description: Code review specialist for quality and security analysis tools: bash model: claude-sonnet-4-5 |
There was a problem hiding this comment.
Example agent frontmatter is invalid YAML
Medium Severity
The reviewer agent header was collapsed into one YAML line, so name, description, tools, and model are no longer separate keys. parseFrontmatter will throw, and loadAgentsFromDir skips agents without both name and description, so this example agent never loads.
Reviewed by Cursor Bugbot for commit 95b8a1c. Configure here.
There was a problem hiding this comment.
🟡 Medium
Line 25 in 95b8a1c
npm run check can rewrite other agents’ unstaged files because the root script runs Biome with --write across the entire worktree. This makes the mandated post-change command violate the shared-worktree safety rules; use a non-mutating check command or limit writes to the files being changed.
🚀 Reply "fix it for me" or copy this AI Prompt for your agent:
In file @AGENTS.md around line 25:
`npm run check` can rewrite other agents’ unstaged files because the root script runs Biome with `--write` across the entire worktree. This makes the mandated post-change command violate the shared-worktree safety rules; use a non-mutating check command or limit writes to the files being changed.
Evidence trail:
AGENTS.md:25, 205-227 at 95b8a1c89f958ca372294eeb73fb61c305c3360f; package.json:17 at REVIEWED_COMMIT
There was a problem hiding this comment.
🟢 Low
Line 87 in 95b8a1c
The runbook fails to start ./prime-agent.sh for checkouts outside /Users/kevin/pi/prime-agent because the hard-coded cd command fails. Replace that path with the current repository path or a clearly documented placeholder.
🚀 Reply "fix it for me" or copy this AI Prompt for your agent:
In file @AGENTS.md around line 87:
The runbook fails to start `./prime-agent.sh` for checkouts outside `/Users/kevin/pi/prime-agent` because the hard-coded `cd` command fails. Replace that path with the current repository path or a clearly documented placeholder.
Evidence trail:
AGENTS.md:82-90 at REVIEWED_COMMIT


Adds
markdownlint-cli2(same tool and rule baseline as research-environments and verifiers) and fixes all existing violations.Config (
.markdownlint-cli2.yaml): MD013 (line length) off, MD024 siblings-only (CHANGELOG### Fixedrepeats per version), MD041 off (several docs open with a callout or centered branding), MD060 compact tables, inline-HTML allowlist for the README branding headers.node_modulesandpackages/coding-agent/distignored.Wiring:
npm run check:md, included innpm run check(~0.6s), so the existing pre-commit hook and CI enforce it without workflow changes.Fixes (96 files linted, was ~1400 violations): almost entirely mechanical via
--fix— blank lines around headings/lists/fences, table pipe spacing, bare URLs wrapped in angle brackets. Manual: language tags on 37 unlabeled code fences, one broken anchor indocs/rpc.md(#message-types→#types), and two duplicate sibling### Addedsections merged inpackages/ai/CHANGELOG.md0.17.0. No prose changes.No CHANGELOG bullet: tooling/docs formatting only, no user-visible behavior.
Note
Low Risk
Dev-only lint tooling and documentation formatting; no application code or security-sensitive paths changed.
Overview
Introduces markdownlint-cli2 with a repo config (
.markdownlint-cli2.yaml) aligned with sibling projects: line length off, sibling-only duplicate headings, compact tables, selective inline HTML allowed, plus a custom no-hard-wraps rule so prose stays on single logical lines.CI enforcement comes from
npm run check:mdon**/*.md, wired into the rootnpm run checkso existing pre-commit/CI paths pick it up without workflow edits.The bulk of the diff is mechanical markdown cleanup across READMEs, CONTRIBUTING, agent docs, and CHANGELOGs: table formatting, fence language tags (often
text), reflowed paragraphs, and a few targeted fixes (e.g. duplicate### Addedsections inpackages/ai/CHANGELOG.md, minor anchor/format tweaks). No product runtime behavior changes.Reviewed by Cursor Bugbot for commit 95b8a1c. Bugbot is set up for automated code reviews on this repo. Configure here.
Note
Add markdownlint and fix violations across all markdown files
markdownlint-cli2as a devDependency and wires it into thecheckscript via a newcheck:mdtask in package.jsonnode_modulesandpackages/coding-agent/distPA001in scripts/markdownlint/no-hard-wraps.cjs that flags hard-wrapped prose lines continuing across lines without an explicit hard breaktextnpm run checknow runs markdown linting, so CI will fail on new violations;PA001flags any non-structural prose line that continues to the next line, so contributors must keep paragraphs on single lines unless a hard break is intended📊 Macroscope summarized 95b8a1c. 23 files reviewed, 2 issues evaluated, 0 issues filtered, 2 comments posted
🗂️ Filtered Issues