Repository navigation
Commands
tells.py is the checker the skill runs. It lives at skills/everwrite/scripts/tells.py, needs Python 3.9 or later and imports only the standard library. Every transcript here ran from a fresh clone of the repository on 2026-10-03. The runs used Windows 11 with Python 3.14.6 and again with 3.9.25, and both printed the same.
python tells.py [--max-words N] [--allow-dashes] [--wiki] [--json] [--list] [--fix-hidden] [paths ...]
A path is a file, a directory or - for stdin. A directory is searched recursively for .md and .txt files, in sorted order; other files are ignored. Files are read as UTF-8, with a byte order mark allowed.
| Option | What it does |
|---|---|
--max-words N |
Flags sentences longer than N words as weak long-sentence hits. The default is 30. |
--allow-dashes |
Turns off the dash rule, for an author whose own writing uses dashes. |
--wiki |
Treats each file name as the page title a GitHub wiki prints, and flags a first heading that repeats it. Files whose names start with _ (the sidebar and footer) are left out of this rule. |
--json |
Prints the hits and the summary as JSON instead of lines. |
--list |
Prints every rule with its severity and hint, then the stock-word list, and exits 0. |
--fix-hidden |
Rewrites each file without invisible characters, with odd spaces turned into plain ones, then checks it. |
-h, --help
|
Prints the help. |
Each hit is one line, file:line: severity category: 'match' (hint), followed by a summary line. With draft.md from Home:
$ python skills/everwrite/scripts/tells.py draft.md
draft.md:3: strong inflation: 'marks a pivotal shift' (state the fact)
draft.md:3: strong residue: 'excited to announce' (say it directly)
draft.md:3: weak vocabulary: 'pivotal' (plain word or cut; never swap for another listed word)
draft.md:4: strong contrast: "It's not just faster, it's" (state the second half directly)
draft.md:4: strong residue: 'Let me know if' (delete the chat wrapper)
tells: 4 strong, 1 weak, 28 words, 1 file(s)
$ echo $?
1The word count covers prose only: headings, tables, code and skipped regions are not counted.
With docs/draft.md (the same draft), docs/notes.txt (the fixed version) and docs/data.json:
$ python skills/everwrite/scripts/tells.py docs
docs\draft.md:3: strong inflation: 'marks a pivotal shift' (state the fact)
docs\draft.md:3: strong residue: 'excited to announce' (say it directly)
docs\draft.md:3: weak vocabulary: 'pivotal' (plain word or cut; never swap for another listed word)
docs\draft.md:4: strong contrast: "It's not just faster, it's" (state the second half directly)
docs\draft.md:4: strong residue: 'Let me know if' (delete the chat wrapper)
tells: 4 strong, 1 weak, 47 words, 2 file(s)Two files were checked; the JSON file was skipped. This run was on Windows, so the path prints with a backslash. On macOS and Linux it would print docs/draft.md (not tested).
$ echo "Great question! Here's a quick overview." | python skills/everwrite/scripts/tells.py -
<stdin>:1: strong residue: 'Great question' (delete the praise)
<stdin>:1: strong residue: "Here's a quick overview" (start with the content)
tells: 2 strong, 0 weak, 6 words, 1 file(s)The same hits as objects, with the summary in its own key:
$ python skills/everwrite/scripts/tells.py --json draft.md
{
"hits": [
{
"line": 3,
"severity": "strong",
"category": "inflation",
"match": "marks a pivotal shift",
"hint": "state the fact",
"file": "draft.md"
},
{
"line": 3,
"severity": "strong",
"category": "residue",
"match": "excited to announce",
"hint": "say it directly",
"file": "draft.md"
},
{
"line": 3,
"severity": "weak",
"category": "vocabulary",
"match": "pivotal",
"hint": "plain word or cut; never swap for another listed word",
"file": "draft.md"
},
{
"line": 4,
"severity": "strong",
"category": "contrast",
"match": "It's not just faster, it's",
"hint": "state the second half directly",
"file": "draft.md"
},
{
"line": 4,
"severity": "strong",
"category": "residue",
"match": "Let me know if",
"hint": "delete the chat wrapper",
"file": "draft.md"
}
],
"summary": {
"strong": 4,
"weak": 1,
"words": 28,
"files": 1
}
}The exit code follows the same rule as the text output. Each match is cut to 70 characters.
A GitHub wiki prints the file name as the page title, so a page Getting-Started.md that opens with # Getting started shows the title twice. The plain check passes it; --wiki does not:
$ python skills/everwrite/scripts/tells.py Getting-Started.md
tells: 0 strong, 0 weak, 7 words, 1 file(s)
$ python skills/everwrite/scripts/tells.py --wiki Getting-Started.md
Getting-Started.md:1: strong repeated-heading: 'Getting started' (the host already prints the page title; start with the first paragraph)
tells: 1 strong, 0 weak, 7 words, 1 file(s)The title is the file name without its extension, with hyphens read as spaces, compared word for word and ignoring case. A page named Home that opens with the project's name passes.
note.md here holds a zero-width space and a no-break space:
$ python skills/everwrite/scripts/tells.py note.md
note.md:1: strong hidden-char: 'U+200B ZERO WIDTH SPACE' (invisible character: delete it (--fix-hidden))
note.md:1: weak odd-space: 'U+00A0 NO-BREAK SPACE' (plain space unless the typography needs it (--fix-hidden))
tells: 1 strong, 1 weak, 10 words, 1 file(s)
$ python skills/everwrite/scripts/tells.py --fix-hidden note.md
fixed note.md: 2 invisible character(s) or odd space(s)
tells: 0 strong, 0 weak, 10 words, 1 file(s)The file is rewritten in place, so keep it under version control or make a copy first. A file that is not valid UTF-8 is left unchanged with a message. --fix-hidden cannot read stdin.
$ python skills/everwrite/scripts/tells.py note.md
note.md:1: strong dash: '—' (use a period, comma, colon or parentheses)
tells: 1 strong, 0 weak, 9 words, 1 file(s)
$ python skills/everwrite/scripts/tells.py --allow-dashes note.md
tells: 0 strong, 0 weak, 9 words, 1 file(s)note.md here is a single sentence of 37 words:
$ python skills/everwrite/scripts/tells.py note.md
note.md:1: weak long-sentence: '37 words: This sentence keeps going with one claus' (split it; one idea per sentence)
tells: 0 strong, 1 weak, 37 words, 1 file(s)
$ python skills/everwrite/scripts/tells.py --max-words 40 note.md
tells: 0 strong, 0 weak, 37 words, 1 file(s)| Code | Meaning |
|---|---|
| 0 | No strong hits. Weak hits may still be listed. Also the code for --list and --help. |
| 1 | At least one strong hit. |
| 2 | Bad input: no path given, a path that does not exist, --fix-hidden with stdin, or an option argparse rejects. |
$ python skills/everwrite/scripts/tells.py
usage: tells.py [-h] [--max-words MAX_WORDS] [--allow-dashes] [--wiki]
[--json] [--list] [--fix-hidden]
[paths ...]
$ echo $?
2
$ python skills/everwrite/scripts/tells.py nothere.md
tells: no such file: nothere.md
$ echo $?
2Hits, the summary line, the JSON, the fixed lines and --list go to standard output. The usage line and the no such file, not UTF-8 and stdin messages go to standard error, so a run with standard error discarded prints nothing and still exits 2:
$ python skills/everwrite/scripts/tells.py nothere.md 2>/dev/null
$ echo $?
2Output is written as UTF-8 whatever the console's code page. Piped through a Windows PowerShell cmdlet, it can still show dashes as odd characters; see the FAQ.
This wiki describes everwrite 1.0.0 (master at 0673975) and was last updated on 2026-10-03. The skill is MIT licensed. Report problems in the issues. Listed in the Claude directory as Everwrite.
Using it
The releases
Contributing
Elsewhere