Writing voices from the output-style catalog, written as Vale rules instead of prompts. Checked on every draft rather than remembered, and free until something breaks one.
Voices requires Vale v3.20.0 or later, and builds on Std, the standard library its length rules extend. Sync pulls Std in automatically; it stays present without being enabled.
Packages = https://github.com/jdkato/voices/releases/latest/download/Voices.zip
[*.md]
BasedOnStyles = Voices, Direct$ vale syncVoices is the shared core and is always on. Add one voice beside it.
| Voice | From | Adds |
|---|---|---|
Voices |
no-ai-slop |
Inflated words, binary contrasts, throat-clearing, puffery, weasel attribution, colon reveals, recap endings, weak verbs |
Direct |
no-slop |
No hedging, no preamble, sentences under 25 words |
GenZ |
gen-z, street |
One slang term a sentence, two a paragraph, at least one |
Coach |
coach |
One note (100 words), one image, one "Next:" action |
Simple |
thing-explainer |
Only the 850 words of Basic English |
The catalog holds dozens of styles; these are the ones that convert into rules a linter can hold. Each covers a different kind of constraint -- patterns, register, structure, vocabulary -- so they compose instead of overlapping.
Coach wants Voices.ColonReveal = NO in your config: its required
Next: label is the colon reveal the shared core forbids.
See vale.sh/blog/voices for one draft run through each voice.
A voice is a named setting of dials, and the dials are addressable. Levels and toggles from your config, as always; scalars with the bracket key:
[*.md]
BasedOnStyles = Voices, Direct
Direct.Length[max] = 30
Voices.ColonReveal = NOTo change what a rule matches, extend it in a style of your own -- your name on the alert, the machinery inherited:
# styles/House/Hedging.yml
extends: Direct.Hedging
message: "We don't hedge."
level: error
tokens+:
- perhaps the best answer is[*.md]
BasedOnStyles = Voices, Direct
House.Hedging = YES
Direct.Hedging = NOThe pair of lines says exactly what happens: your rule in, its parent out. The
disable matters -- the child matches everything its parent does, and with both
enabled every hedge would be reported twice. Leave both on only when that's
the intent: a broad parent at suggestion under a narrowed child at error
is a legitimate shape.
Install the Vale agent tools plugin:
/plugin marketplace add vale-cli/agent-tools
/plugin install vale@agent-tools
Every prose file Claude writes is linted, and the alerts go back into the same turn. Rules with one right answer carry the replacement, so those are applied without a decision.
Tip
The hook relays errors only. Simple is advisory by design. Widen the hook's level in /plugin, or raise a rule with Simple.Vocabulary = error.
To prime the model as well as check it, briefs/ holds a generated summary per voice: cat briefs/Core.md briefs/Direct.md >> CLAUDE.md.
Outside Claude Code, Vale reads stdin and sets an exit code:
$ vale --ext=.md --output=JSON < draft.mdThe core's word lists and patterns come from no-ai-slop by Peter Yang, MIT. The voices follow awesome-claude-output-styles by Serge Shima, also MIT. Simple uses Basic English, C. K. Ogden's 850-word vocabulary from 1930.
NOTICE has the full attribution, and ships inside the archive.
$ ./test.shOne draft against every voice, compared to a golden file; then each rewrite, required to produce nothing. A Vale rule that matches nothing fails silently, so the paired fixture is what tells "no violations" from "no rule". test.sh expects a Std checkout beside this repository, or STD pointing at one.
MIT.