Summary
typos-format rewrites the content of the user's files on every Write/Edit of every file type
and, on the path where it succeeds, says nothing at all. A correction drawn from typos-cli's built-in
dictionary that is wrong for the repository — an acronym, an identifier, a proper noun mapped to an
unrelated English word — therefore lands in the file invisibly and is indistinguishable from a benign
reformat.
Observed in a real consuming session: multiple evidence files silently corrupted, a self-contradicting
line in a written record, and a test fixture name made ambiguous. The corrupting hook was never named
once across the whole session.
Why it is invisible
plugins/typos-format/hooks/typos-format.sh runs typos --write-changes --force-exclude --format json
and inspects the result only when it is non-zero.
Verified empirically against typos-cli 1.44.0: --write-changes emits nothing for a correction it
applies. A file whose findings are all auto-fixable exits 0 with completely empty stdout after
rewriting the file:
$ typos --format json work.txt # read-only
{"type":"typo",...,"typo":"teh","corrections":["the"]}
RC=2
$ typos --write-changes --format json work.txt
RC=0
OUTPUT=[] # nothing. The rewrite is unreported.
So the RC-0 branch has no information to report even if it wanted to, and it emits no
additionalContext, no systemMessage — telemetry only. The harness's own signal is a generic
"PostToolUse hook modified <file> after your edit (likely a formatter)" line that names no hook and
shows no diff, and the hooks reference (https://code.claude.com/docs/en/hooks, fetched 2026-07-26)
documents no file-change or diff channel a hook could use instead.
Second half: the remediation advice is on the wrong branch
The hook already knows the right fix — "if intentional, add it to extend-words /
extend-identifiers in your typos config" — but that text sits only on the residual-findings branch,
which by construction fires for findings that were not applied. It therefore never fires for the
corrections that actually change file content.
This matters because the autocorrect has no memory. Repairing a mangled word by hand gets it
re-corrected on the very next save; the allow-list entry is the only thing that stops it, and nothing
told the user that.
Expected
- Every correction the hook applies is reported: the token, its replacement, and the line — on the
agent channel and on the user channel, since the person whose file changed is the only one who
can judge whether the change was correct.
- The allow-list remediation rides on the applied-correction path, not only the residual one.
- The disclosure is bounded, so a file with hundreds of corrections cannot turn the fix into a
context flood.
- A way to run the hook report-only, without modifying files at all.
Also in scope
plugins/typos-format/hooks/typos-format.test.sh skips its entire suite when no typos binary is
present — which is the CI runner's state. Nothing about this hook is gated in CI today, so a
regression in the disclosure contract would land green.
Environment
typos-cli 1.44.0, Windows 11 / Git Bash. The dictionary corrections are typos-cli-version-specific;
the invisibility is not.
Summary
typos-formatrewrites the content of the user's files on everyWrite/Editof every file typeand, on the path where it succeeds, says nothing at all. A correction drawn from typos-cli's built-in
dictionary that is wrong for the repository — an acronym, an identifier, a proper noun mapped to an
unrelated English word — therefore lands in the file invisibly and is indistinguishable from a benign
reformat.
Observed in a real consuming session: multiple evidence files silently corrupted, a self-contradicting
line in a written record, and a test fixture name made ambiguous. The corrupting hook was never named
once across the whole session.
Why it is invisible
plugins/typos-format/hooks/typos-format.shrunstypos --write-changes --force-exclude --format jsonand inspects the result only when it is non-zero.
Verified empirically against typos-cli 1.44.0:
--write-changesemits nothing for a correction itapplies. A file whose findings are all auto-fixable exits
0with completely empty stdout afterrewriting the file:
So the RC-0 branch has no information to report even if it wanted to, and it emits no
additionalContext, nosystemMessage— telemetry only. The harness's own signal is a generic"PostToolUse hook modified
<file>after your edit (likely a formatter)" line that names no hook andshows no diff, and the hooks reference (https://code.claude.com/docs/en/hooks, fetched 2026-07-26)
documents no file-change or diff channel a hook could use instead.
Second half: the remediation advice is on the wrong branch
The hook already knows the right fix — "if intentional, add it to
extend-words/extend-identifiersin your typos config" — but that text sits only on the residual-findings branch,which by construction fires for findings that were not applied. It therefore never fires for the
corrections that actually change file content.
This matters because the autocorrect has no memory. Repairing a mangled word by hand gets it
re-corrected on the very next save; the allow-list entry is the only thing that stops it, and nothing
told the user that.
Expected
agent channel and on the user channel, since the person whose file changed is the only one who
can judge whether the change was correct.
context flood.
Also in scope
plugins/typos-format/hooks/typos-format.test.shskips its entire suite when notyposbinary ispresent — which is the CI runner's state. Nothing about this hook is gated in CI today, so a
regression in the disclosure contract would land green.
Environment
typos-cli 1.44.0, Windows 11 / Git Bash. The dictionary corrections are typos-cli-version-specific;
the invisibility is not.