adhd-md

Agent skill · works in six agents

Make your Markdown
readable

Conclusion first, short chunks, clear next steps. The same skill works in Claude Code, Codex, Grok Build, Gemini CLI, Cursor, and opencode.

Rearrange information. Never delete it. Too long? Collapse it or move it to an appendix. Format-mode changes are provably lossless.

npx github:tsonglew/adhd-md
01

Unreadable docs are usually a layout problem

The same information, unreadable as a blob, readable once it's cut up. Nothing in the content changes.

md-cache is a Markdown rendering cache middleware that stores render results on disk keyed by content hash, and returns them directly on hit so nothing renders twice. It requires Node 18+, and its only dependency is lru-cache. Once installed, wrap your rendering pipeline with withCache. The cache directory defaults to .cache/md, and you can change it with the MD_CACHE_DIR environment variable. The default entry limit is 500, changeable via the maxEntries option. The default TTL is 7 days, changeable via the ttl option in milliseconds. Setting it to 0 means never expire, but the disk grows forever, which production environments should avoid.

  • Back-references“As mentioned above” makes your eyes go back, relocate, and return. One full working-memory reset, for free
  • Buried conclusionReaders decide in the first 15 lines whether to stay. A conclusion on line 40 might as well not exist
  • No next stepYou know the theory but not what to type. Startup friction becomes abandonment
  • AI slop“It's not X, it's Y” makes readers load a misconception they never had, then unload it
02

Same document, not a single word changed

This is real corpus material. scope=format only touches markup, whitespace, and block order — the word sequence stays verbatim. Compare the two sides.

Before 87.8

md-cache

md-cache is a Markdown rendering cache middleware that stores render results on disk keyed by content hash, and returns them directly on hit so nothing renders twice. It requires Node 18+, and its only dependency is lru-cache. Once installed, wrap your rendering pipeline with withCache. The cache directory defaults to .cache/md, and you can change it with the MD_CACHE_DIR environment variable. The default entry limit is 500, changeable via the maxEntries option. The default TTL is 7 days, changeable via the ttl option in milliseconds. Setting it to 0 means never expire, but the disk grows forever, which production environments should avoid.

If your render function has side effects, don't use this middleware, because on a cache hit the render function never runs. If your Markdown embeds timestamps or random values, the output gets frozen by the cache and looks like it never refreshes. That's not a bug.

Measured on a site with 1,200 documents: cold build 42 seconds, second build 3.1 seconds. Thirteen times faster.

After 100

md-cache

Measured on a site with 1,200 documents: cold build 42 seconds, second build 3.1 seconds. Thirteen times faster.

md-cache is a Markdown rendering cache middleware that stores render results on disk keyed by content hash, and returns them directly on hit so nothing renders twice.

It requires Node 18+, and its only dependency is lru-cache. Once installed, wrap your rendering pipeline with withCache.

  • The cache directory defaults to .cache/md, changeable via the MD_CACHE_DIR environment variable.
  • The default entry limit is 500, changeable via the maxEntries option.
  • The default TTL is 7 days, changeable via the ttl option, in milliseconds.
  • Setting it to 0 means never expire, but the disk grows forever. Avoid in production.

If your render function has side effects, don't use this middleware, because on a cache hit the render function never runs.

If your Markdown embeds timestamps or random values, the output gets frozen by the cache and looks like it never refreshes. That's not a bug.

Conclusion first
Chunking
Scannability
Sentence load
Actionability
Consistency
Human voice

Changed: moved the conclusion up, split one blob into four paragraphs, turned four config sentences into a list, wrapped bare identifiers in code. Words added: 0. Words deleted: 0.

Notice what the fixed version doesn't do: no heading above the config list. The word “Configuration” isn't in the original — adding it would be new wording, which crosses into content. You can restructure everything, but you can't touch a single word. That's the ceiling of format mode, and it's the point.

03

Format only, content only, or both

One line draws the boundary. Moving an existing block is format. Writing a new sentence is content.

format

The word sequence stays verbatim. Only markup, whitespace, and block order change.

Can do

Split paragraphs at existing sentence breaks · turn parallel sentences into lists (reusing the words) · bold existing terms · reorder blocks · add code fence language tags · collapse sections · fix CJK spacing and punctuation

Can't do

Change a single word · write a new TL;DR · reword headings

Provably lossless

content

Only wording and information structure change. Layout stays untouched.

Can do

Split long sentences · passive to active · write a TL;DR · conclusion-style headings · add time estimates and next steps · explain terms on first use · cut filler

Can't do

Touch layout · delete constraints, units, versions, or edge cases in the name of “tightening”

Invariants preserved

bothdefault

Content first, then format, then one combined check.

The other axis

light does zero-risk fixes only, for specs and API docs. standard splits, lists, retitles, and writes a TL;DR. deep rebuilds the whole skeleton, for meeting notes and messy drafts.

How to use it

Just say it in plain words: “Make README.md ADHD-friendly, format only”

75 rules filtered by axis and level

04

While it's here, it also strips AI slop

Model-written Chinese has a fixed set of routines. Each one costs the reader an extra bit of attention, so they belong to this skill.

RoutineAttention the reader pays
It's not X. It's Y.Load a misconception you never had, then unload it. One working-memory reset, for free
The core is:Announces importance before delivering the goods — the sentence says itself twice
It's worth notingPromises depth, delivers none. One attention unit, stolen
Completed an optimization of…The verb hides inside a noun. One extra parse to find out who did what
leverage, synergy, end-to-endPlain words carry the same information, minus the translation step
Time will keep the detailsNo subject to hold accountable. Nothing to verify
extensive tests, various scenariosQuantities without numbers carry no information
significantly better, fully solvesNo number, nothing to verify

Em dashes aren't banned. Their density is.

An is a normal piece of punctuation, fine for a parenthetical. The tell is using it as a rhythm crutch. Hand-written tech docs average about 5 per 1,000 characters; model output often runs above 15. Threshold: 8. And only prose counts — item — owner — due inside list items is field separation, not rhythm.

What a regex can't tell, a model judges

Three flags in parallel is good writing. “Why we left, why we failed, why we still try” is what needs fixing. A regex can't tell them apart, so anaphora and metaphor are flagged for review, not docked points. git repo is literal; “a repository of memories” is packaging.

05

Delete one word and it gets rejected

In format mode, the token multiset of the prose, with markup stripped, must match exactly. A missing token is missing, new wording is added — both refuse to write back.

What's computable never goes to a model

Audit, format fixes, and lossless verification all live in one pure-stdlib Python file. Same process, not same model — so the scores and checks come out identical across all six hosts.

Scores don't inflate themselves

Of the 75 rules, 44 are script-checkable (42 score, 2 advisory) and 31 need model judgment. audit prints a “script score” and never a grade. A low script score always means problems; a high one doesn't always mean none.

06

One skill, six agents

All six hosts natively support the same SKILL.md directory format, so there's nothing to adapt. The canonical skill lives in ~/.agents/skills/, each host gets a symlink — change it once, it changes everywhere.

  • Claude Code ~/.claude/skills/ tested at runtime
  • Codex ~/.codex/skills/ tested at runtime
  • Grok Build ~/.grok/skills/ tested for loading
  • Gemini CLI ~/.gemini/skills/ tested for loading
  • Cursor ~/.cursor/skills/ tested for loading
  • opencode ~/.config/opencode/skills/ tested for loading

Codex ran the whole workflow headless, noticed the target file had uncommitted changes, and wrote to a side file instead of overwriting it — exactly what step 0 of the skill says. Its output differs from my hand-written example, but passes just the same. It merged two warnings into one blockquote; I turned the config into a list. Both scored 100, both changed zero words.

The other four hosts are only verified to load the skill, not to run it well. Verification notes list what's been checked, what hasn't, and the known limits.

07

Installed in two minutes

  1. Install. Any of the three ways works — the script detects which agents you have and only touches those hosts.

    With Node

    npx github:tsonglew/adhd-md

    Without Node

    curl -fsSL https://tsonglew.github.io/adhd-md/install.sh | bash

    To hack on the source

    git clone https://github.com/tsonglew/adhd-md && cd adhd-md bash scripts/install.sh

    The git-clone install is a symlink — git pull updates it. The npx and curl installs copy the skill — rerun to update.

  2. Audit something first and see the score and the findings list.

    npx github:tsonglew/adhd-md audit your-doc.md
  3. Then just say it in plain words to any agent.

    Make README.md ADHD-friendly, format only

CI

adhd_md.py fmt --check docs/*.md adhd_md.py audit --min-score 70 docs/*.md

No command execution available

Web-chat LLMs can paste the self-contained single file, adhd-md.standalone.md, 30 KB with all rules. The catch: no machine checks — say so in your report.