Skip to content
Workflow

Writing rules that avoid AI-sounding prose

Rules and a linter that stop agents writing 'seamlessly empowers', 'not just X, it's Y', fake proof and em-dash runs into your docs, PRs and release notes.

Verified install Not agent-tested v1.0.0 MIT updated anymarkdown
Equips
  • 1 1 Rules
  • 1 1 Skills
  • – 0 MCP

Readers now spot machine prose in a sentence and stop trusting the page. The tells are well documented: inflated words like delve, tapestry and pivotal, 'it's not just X, it's Y', reflexive groups of three, em-dash runs, emoji bullets, chat filler and proof nobody can check. This loadout gives the agent plain-English rules for every file it writes, a word list with the plain alternative for each pattern, and a standard-library linter that skips code and quotations. The verifier runs the linter on a sloppy README (22 findings) and on a plain rewrite (none).

What's in it

  • Rules for docs, READMEs, PRs, commit messages, release notes and UI copy
  • Word list with the plain alternative for each pattern, UK spelling
  • Linter skips fenced code, inline code, quotes and front matter
  • Flags fake proof such as '10,000+ users' and 'trusted by thousands'
  • Allow-list for deliberate exceptions

You'll need

  • Tools: python3
Level 1 · automated

Verification

Verified install

Checked at commit 021470d · 9 passed, 0 failed, 1 not applicable

CheckResultWhat we found
Listinglisting.yaml matches the schema and declares every file in the folder. Pass
Schema valid; 6 files declared, none missing or extra
  • tested.status: untested (agent tests are separate from Level 1)
Files parseJSON parses; SKILL.md and .mdc front matter is valid YAML with the fields each agent needs; code fences are closed. Pass All 6 files parse; front matter valid
AdaptersCLAUDE.md imports @AGENTS.md, GEMINI.md imports @./AGENTS.md, and both match the generator. Pass
CLAUDE.md and GEMINI.md import AGENTS.md and are up to date
  • CLAUDE.md: matches the generator
  • GEMINI.md: matches the generator
Install pathsEvery file lands where each agent documents it, with no collisions, and the laid-out project is re-discovered correctly. Pass
Correct paths for all 6 agents; layouts re-discovered
  • Claude Code: 5 files, 1 skill in .claude/skills/
  • Codex CLI: 4 files, 1 skill in .agents/skills/
  • Cursor: 4 files, 1 skill in .agents/skills/
  • Gemini CLI: 5 files, 1 skill in .agents/skills/
  • Antigravity CLI: 4 files, 1 skill in .agents/skills/
  • GitHub Copilot: 4 files, 1 skill in .agents/skills/
MCP configmcp.json is structurally valid, converts to each agent's format, declares no literal secrets, and referenced packages exist on npm/PyPI. Not applicable No MCP servers in this loadout
Safety scanThe intake scanner finds no credentials, risky shell, hidden Unicode or prompt-injection wording, and the listing's network flag is honest. Pass
Clean: no credentials, risky shell or hidden text
  • Scanner intake-precheck/1: verdict clean; network no (listing says no)
ReferencesLinks and file paths between the loadout's files resolve, including for each agent's installed layout. Pass 4 references between files resolve for every agent
Size limitsFile count and sizes are within the submission limits; SKILL.md bodies stay under 500 lines. Pass
6 files, 11.1 KB total; largest skills/plain-prose/scripts/prose_lint.py 5.3 KB
  • Limits: 30 files, 32 KB per file, 128 KB total, 500 lines per skill or rule
LicenceA recognised SPDX licence, with the licence text available. Pass MIT, by Agent Loadout; text in the repository LICENSE
Starter buildA minimal fixture project with the loadout applied installs and builds or type-checks, and the loadout's own code examples compile. Pass
The plain-prose linter finds 22 machine-prose tells in a sloppy README (vocabulary, 'not just X, it's Y', fake proof, em-dash runs, emoji bullets, chat filler) while ignoring code and quotes, and passes a plain rewrite
  • Applied 9 loadout files at every agent's paths
  • ✓ sloppy README is flagged: bash -c python3 .agents/skills/plain-prose/scripts/prose_lint.py sloppy.md; echo "exit=$?"
  • ✓ plain rewrite passes: python3 .agents/skills/plain-prose/scripts/prose_lint.py plain.md
  • ✓ allow-list and dash limit: bash -c python3 .agents/skills/plain-prose/scripts/prose_lint.py --allow crucial,robust --max-dashes 3 sloppy.md | tail -n 1
  • Covers: Inflated vocabulary with plain alternatives
  • Covers: Constructions: not just X it's Y, plays a crucial role, stands as a, chat openers and closers
  • Covers: Unverifiable proof, em-dash runs, emoji bullets and bold spam
  • Covers: Fenced code, inline code, block quotes and front matter are skipped

What this means: a script checked the files themselves: they parse, they install where each agent looks, any MCP config is sound, the safety scan is clean, references between files resolve, and, where a free and repeatable fixture exists, a small starter project builds with the loadout applied. No AI agent was run. Per-agent results ("tested with agent") are separate and stay untested until an agent actually runs.

Install

Choose your agent. Run the commands from your project root, or download a zip already laid out in the right folders.

Claude Code reads CLAUDE.md (imports AGENTS.md with @AGENTS.md) and skills from .claude/skills/.

Download zip
curl -fsSL --create-dirs -o AGENTS.md https://loadout.jnw-it.com/raw/no-ai-voice-writing/1.0.0/AGENTS.md
curl -fsSL --create-dirs -o CLAUDE.md https://loadout.jnw-it.com/raw/no-ai-voice-writing/1.0.0/CLAUDE.md
curl -fsSL --create-dirs -o .claude/skills/plain-prose/SKILL.md https://loadout.jnw-it.com/raw/no-ai-voice-writing/1.0.0/skills/plain-prose/SKILL.md
curl -fsSL --create-dirs -o .claude/skills/plain-prose/scripts/prose_lint.py https://loadout.jnw-it.com/raw/no-ai-voice-writing/1.0.0/skills/plain-prose/scripts/prose_lint.py
curl -fsSL --create-dirs -o .claude/skills/plain-prose/references/word-list.md https://loadout.jnw-it.com/raw/no-ai-voice-writing/1.0.0/skills/plain-prose/references/word-list.md
FileGoes to
AGENTS.mdAGENTS.md
CLAUDE.mdCLAUDE.md
skills/plain-prose/SKILL.md.claude/skills/plain-prose/SKILL.md
skills/plain-prose/scripts/prose_lint.py.claude/skills/plain-prose/scripts/prose_lint.py
skills/plain-prose/references/word-list.md.claude/skills/plain-prose/references/word-list.md

Already have an AGENTS.md or CLAUDE.md? The commands above overwrite it — download the file instead and merge the sections you want.

Files

Rules AGENTS.md Plain-writing rules for every file and reply the agent writes. 23 lines
Download Raw
# AGENTS.md: write like a person, not a press release

Applies to everything you write for this project: docs, READMEs, commit messages, PR descriptions, release notes,
changelogs, UI copy and replies to the user. Readers now recognise machine prose on sight and stop trusting it.

## Rules
- Say the thing. Lead with the fact, the number or the instruction. No warm-up sentence, no summary of what you are
  about to say, no closing recap.
- Plain words. "Use" not "leverage", "has" not "boasts", "important" only when you say why. The `plain-prose` skill has the full word list.
- No inflated significance: nothing is a "testament", a "tapestry", "pivotal", "game-changing" or "a journey".
- No "it's not just X, it's Y" and no "not only X but also Y". State what it is.
- No reflexive groups of three. Use the number of items there are.
- Punctuation: full stops and commas. At most one em dash per paragraph; prefer a colon, comma or new sentence.
- No emoji as bullets or headings. No bold on every other phrase. Sentence-case headings.
- No unverifiable proof: "trusted by thousands", "10,000+ users", "industry-leading". Give a source or cut it.
- No chat filler in files: "Great question", "I hope this helps", "Let's dive in", "Certainly!".
- Be specific. Replace "improves performance" with the measurement, "various issues" with the issues.
- Follow the project's spelling. This project uses UK English unless a file already uses another variant.

## Check before you finish
- Run the `plain-prose` skill's linter (`scripts/prose_lint.py` in the skill folder) on prose you wrote or changed. Fix every finding or explain why it stays. Use the `plain-prose` skill for rewrites.
- Code, identifiers and quoted text are exempt. Do not "fix" a word inside backticks or a quotation.
Adapter CLAUDE.md Imports AGENTS.md for Claude Code. 10 lines
Download Raw
# CLAUDE.md

@AGENTS.md

## Claude Code notes
- Skills from this loadout live in `.claude/skills/`: `plain-prose`. Use them when their description matches the task.
- Follow AGENTS.md above; where this file and AGENTS.md disagree, AGENTS.md wins.

<!-- From the Agent Loadout "Writing rules that avoid AI-sounding prose" v1.0.0 — https://loadout.jnw-it.com/loadouts/no-ai-voice-writing/ -->
Adapter GEMINI.md Imports AGENTS.md for Gemini CLI. 10 lines
Download Raw
# GEMINI.md

@./AGENTS.md

## Gemini CLI notes
- Skills from this loadout live in `.agents/skills/`: `plain-prose`. Use them when their description matches the task.
- Follow AGENTS.md above; where this file and AGENTS.md disagree, AGENTS.md wins.

<!-- From the Agent Loadout "Writing rules that avoid AI-sounding prose" v1.0.0 — https://loadout.jnw-it.com/loadouts/no-ai-voice-writing/ -->
Skill skills/plain-prose/SKILL.md Lint, rewrite and re-check prose. 24 lines
Download Raw
---
name: plain-prose
description: Rewrite or check prose so it does not read as machine-written. Use for READMEs, docs, release notes, PR descriptions, commit messages and UI copy, before showing them to the user.
---

# Plain prose

1. Lint first: `python3 scripts/prose_lint.py <file> [<file> ...]`. It skips fenced code, inline code and block
   quotes, and prints `path:line rule "match" -> suggestion`. Exit code 1 means there are findings.
2. Fix each finding by rewriting the sentence, not by swapping in a synonym. Most findings mean the sentence has no
   content: delete it, or replace it with the specific fact it was gesturing at.
3. Read `references/word-list.md` for the patterns and the plain alternatives.
4. Re-run the lint until it is clean, or until every remaining finding is deliberate (a quotation, a product name).
   Pass `--allow word` for a deliberate exception and say why in your reply.
5. Read the result aloud in your head. If a sentence would sound odd said to a colleague, rewrite it.

## Before and after
- Before: "This powerful tool seamlessly empowers teams to unlock their full potential."
  After: "Runs the test suite on every push and posts failures to the PR."
- Before: "It's not just a linter, it's a complete quality journey."
  After: "It lints Markdown and checks links."
- Before: "Trusted by 10,000+ developers worldwide."
  After: cut it, or "Downloaded 12,400 times last month (npm, October 2026)."
Skill file skills/plain-prose/scripts/prose_lint.py Standard-library linter for machine-prose patterns. 120 lines
Download Raw
#!/usr/bin/env python3
"""Flag prose patterns that read as machine-written.

Usage: python3 prose_lint.py [--allow word,word] [--max-dashes N] FILE [FILE ...]
Skips fenced code blocks, inline code, block quotes and YAML front matter.
Prints "path:line rule "match" -> suggestion" and exits 1 if anything is found. Standard library only.
"""
import re
import sys

W = r"\b"
VOCAB = [
    (r"delv(?:e|es|ed|ing)|deep[- ]dive", "look at, read, check"),
    (r"leverag(?:e|es|ed|ing)", "use"),
    (r"utili[sz](?:e|es|ed|ing|ation)", "use"),
    (r"boasts", "has"),
    (r"seamless(?:ly)?", "say what happens, or cut"),
    (r"robust(?:ly|ness)?", "say what it withstands"),
    (r"tapestry|testament", "cut"),
    (r"pivotal|crucial", "important, and say why"),
    (r"underscor(?:e|es|ed|ing)", "show"),
    (r"showcas(?:e|es|ed|ing)", "show"),
    (r"foster(?:s|ed|ing)?", "build, encourage"),
    (r"empower(?:s|ed|ing)?|unlock(?:s|ed|ing)? (?:the |your |their )?(?:full )?potential|elevat(?:e|es|ed|ing) your", "say what it lets someone do"),
    (r"cutting[- ]edge|game[- ]chang(?:er|ing)|revolutionary|next[- ]level|best[- ]in[- ]class|industry[- ]leading", "cut"),
    (r"vibrant|intricate|meticulous(?:ly)?|multifaceted", "cut, or be specific"),
    (r"navigat(?:e|ing) the (?:complexities|challenges|world)", "handle, deal with"),
    (r"ever[- ](?:evolving|changing) (?:landscape|world)|in the (?:\w+ )?landscape of", "cut"),
    (r"(?:a|the|this|your) journey", "cut (figurative 'journey')"),
]
PHRASES = [
    ("not-just", r"\b(?:it'?s|this is|is) not just (?:a |an |about )?[^.,;]{1,40}[,;:]\s*(?:it'?s|but)\b", "say what it is"),
    ("not-only", r"\bnot only\b[^.]{1,80}\bbut also\b", "say what it is"),
    ("whether-youre", r"\bwhether you'?re (?:a |an )?\w+ or\b", "cut"),
    ("fast-paced", r"\bin today'?s (?:fast[- ]paced|digital|modern) (?:world|age|landscape)\b", "cut"),
    ("serves-as", r"\b(?:stands|serves) as (?:a|an|the)\b", "is"),
    ("plays-a-role", r"\bplays? an? (?:crucial|key|pivotal|vital|important) role\b", "say what it does"),
    ("chat-opener", r"^(?:certainly|absolutely|great question|of course)[!,.]", "cut"),
    ("chat-closer", r"\b(?:i hope this helps|let me know if you (?:have|need)|happy to help)\b", "cut"),
    ("lets-dive", r"\blet'?s (?:dive|jump|get started)\b", "cut"),
    ("recap", r"^(?:in conclusion|in summary|overall),", "cut the recap"),
    ("additionally", r"^additionally,", "also, or a new paragraph"),
    ("unverified-proof", r"\b\d{1,3}(?:,\d{3})+\+|\btrusted by (?:thousands|millions|teams|developers)\b", "give a source and date, or cut"),
]
EMOJI_BULLET = re.compile(r"^\s*(?:[-*]\s+)?[\U0001F300-\U0001FAFF\u2600-\u27BF\u2705\u274C]\s*\S|^#+\s*[\U0001F300-\U0001FAFF\u2600-\u27BF]")
DASH = "\u2014"


def strip_inline(line):
    return re.sub(r"`[^`]*`", lambda m: " " * len(m.group(0)), line)


def lint(path, allow, max_dashes):
    out = []
    with open(path, encoding="utf-8") as fh:
        lines = fh.read().splitlines()
    in_code = False
    in_front = bool(lines) and lines[0].strip() == "---"
    para_dashes = 0
    vocab = [(re.compile(W + "(?:" + p + ")" + W, re.I), s) for p, s in VOCAB]
    phrases = [(n, re.compile(p, re.I), s) for n, p, s in PHRASES]
    for n, raw in enumerate(lines, 1):
        if in_front:
            if n > 1 and raw.strip() == "---":
                in_front = False
            continue
        if raw.lstrip().startswith(("```", "~~~")):
            in_code = not in_code
            continue
        if in_code or raw.lstrip().startswith(">"):
            continue
        if not raw.strip():
            para_dashes = 0
            continue
        line = strip_inline(raw)
        text = re.sub(r"^\s*(?:[-*+]|\d+\.)\s+", "", line)
        text = re.sub(r"^#+\s*", "", text).strip()
        for rx, sugg in vocab:
            for m in rx.finditer(line):
                if m.group(0).lower() not in allow:
                    out.append((n, "ai-vocabulary", m.group(0), sugg))
        for name, rx, sugg in phrases:
            m = rx.search(text)
            if m and m.group(0).lower() not in allow:
                out.append((n, name, m.group(0), sugg))
        if EMOJI_BULLET.search(line):
            out.append((n, "emoji-bullet", line.strip()[:20], "plain bullet or heading"))
        if len(re.findall(r"\*\*[^*]+\*\*", line)) >= 3:
            out.append((n, "bold-spam", "**", "bold one thing at most"))
        para_dashes += line.count(DASH)
        if line.count(DASH) and para_dashes > max_dashes:
            out.append((n, "em-dash", DASH, "colon, comma or a new sentence"))
    return [(path, *f) for f in out]


def main(argv):
    allow, max_dashes, files = set(), 1, []
    it = iter(argv[1:])
    for a in it:
        if a == "--allow":
            allow |= {w.strip().lower() for w in next(it, "").split(",") if w.strip()}
        elif a == "--max-dashes":
            max_dashes = int(next(it, "1"))
        else:
            files.append(a)
    if not files:
        print(__doc__.strip())
        return 2
    findings = []
    for f in files:
        findings += lint(f, allow, max_dashes)
    for path, n, rule, match, sugg in findings:
        print(f'{path}:{n} {rule} "{match}" -> {sugg}')
    print(f"{len(findings)} finding{'s' if len(findings) != 1 else ''} in {len(files)} file{'s' if len(files) != 1 else ''}")
    return 1 if findings else 0


if __name__ == "__main__":
    sys.exit(main(sys.argv))
Skill file skills/plain-prose/references/word-list.md Patterns and plain alternatives. 44 lines
Download Raw
# Word list: patterns that read as machine-written

Patterns, not banned words. "Key" is fine in "API key"; "landscape" is fine for a painting. The linter flags
figurative uses where it can; you decide.

## Inflated vocabulary (use the plain word or cut)
| Pattern | Instead |
| --- | --- |
| delve, deep dive | look at, read, check |
| leverage | use |
| utilise | use |
| boasts | has |
| seamless, seamlessly | say what actually happens, or cut |
| robust | say what it withstands |
| tapestry, testament, journey (figurative) | cut |
| pivotal, crucial, vital | important, and say why |
| underscore, highlight (as verbs for ideas) | show |
| showcase, showcasing | show |
| foster, fostering | build, encourage |
| empower, unlock, elevate | let, allow, improve (with a number) |
| cutting-edge, game-changing, revolutionary, next-level | cut |
| vibrant, intricate, meticulous, multifaceted | cut, or be specific |
| navigate (the complexities of) | handle, deal with |
| in the ever-evolving landscape of | cut |
| additionally (opening a sentence) | also, or start a new paragraph |

## Constructions
- "It's not just X, it's Y" / "not only X but also Y": say what it is.
- "Whether you're a beginner or an expert": cut.
- "In today's fast-paced world": cut.
- "Stands as a", "serves as a": "is".
- "Plays a crucial role in": say what it does.
- Opening chat: "Certainly!", "Great question", "Absolutely". Closing chat: "I hope this helps", "Let me know if".
- "In conclusion", "Overall,", "In summary," at the end of a short text: cut the recap.

## Punctuation and layout
- Em dashes: at most one per paragraph.
- Emoji used as bullets or before headings.
- Bold on several phrases in one paragraph.
- Title Case Headings: use sentence case.

## Proof
- "Trusted by thousands", "10,000+ users", "industry-leading", "best-in-class": give a source and date, or cut.

All files: source zip · Licence MIT · By Agent Loadout · First listed

Installing and testing

How do I install Writing rules that avoid AI-sounding prose in Claude Code?

From your project root, put AGENTS.md, CLAUDE.md, skills/plain-prose/SKILL.md at .claude/skills/plain-prose/SKILL.md, skills/plain-prose/scripts/prose_lint.py at .claude/skills/plain-prose/scripts/prose_lint.py, skills/plain-prose/references/word-list.md at .claude/skills/plain-prose/references/word-list.md. The "Claude Code" tab on this page has the curl commands, or download https://loadout.jnw-it.com/download/no-ai-voice-writing/claude-code.zip, which is already laid out. Do not overwrite an existing AGENTS.md or CLAUDE.md; merge it.

How do I install Writing rules that avoid AI-sounding prose in Codex CLI?

From your project root, put AGENTS.md, skills/plain-prose/SKILL.md at .agents/skills/plain-prose/SKILL.md, skills/plain-prose/scripts/prose_lint.py at .agents/skills/plain-prose/scripts/prose_lint.py, skills/plain-prose/references/word-list.md at .agents/skills/plain-prose/references/word-list.md. The "Codex CLI" tab on this page has the curl commands, or download https://loadout.jnw-it.com/download/no-ai-voice-writing/codex.zip, which is already laid out. Do not overwrite an existing AGENTS.md or CLAUDE.md; merge it.

How do I install Writing rules that avoid AI-sounding prose in Cursor?

From your project root, put AGENTS.md, skills/plain-prose/SKILL.md at .agents/skills/plain-prose/SKILL.md, skills/plain-prose/scripts/prose_lint.py at .agents/skills/plain-prose/scripts/prose_lint.py, skills/plain-prose/references/word-list.md at .agents/skills/plain-prose/references/word-list.md. The "Cursor" tab on this page has the curl commands, or download https://loadout.jnw-it.com/download/no-ai-voice-writing/cursor.zip, which is already laid out. Do not overwrite an existing AGENTS.md or CLAUDE.md; merge it.

How do I install Writing rules that avoid AI-sounding prose in Gemini CLI?

From your project root, put AGENTS.md, GEMINI.md, skills/plain-prose/SKILL.md at .agents/skills/plain-prose/SKILL.md, skills/plain-prose/scripts/prose_lint.py at .agents/skills/plain-prose/scripts/prose_lint.py, skills/plain-prose/references/word-list.md at .agents/skills/plain-prose/references/word-list.md. The "Gemini CLI" tab on this page has the curl commands, or download https://loadout.jnw-it.com/download/no-ai-voice-writing/gemini-cli.zip, which is already laid out. Do not overwrite an existing AGENTS.md or CLAUDE.md; merge it.

How do I install Writing rules that avoid AI-sounding prose in Antigravity CLI?

From your project root, put AGENTS.md, skills/plain-prose/SKILL.md at .agents/skills/plain-prose/SKILL.md, skills/plain-prose/scripts/prose_lint.py at .agents/skills/plain-prose/scripts/prose_lint.py, skills/plain-prose/references/word-list.md at .agents/skills/plain-prose/references/word-list.md. The "Antigravity CLI" tab on this page has the curl commands, or download https://loadout.jnw-it.com/download/no-ai-voice-writing/antigravity-cli.zip, which is already laid out. Do not overwrite an existing AGENTS.md or CLAUDE.md; merge it.

How do I install Writing rules that avoid AI-sounding prose in GitHub Copilot?

From your project root, put AGENTS.md, skills/plain-prose/SKILL.md at .agents/skills/plain-prose/SKILL.md, skills/plain-prose/scripts/prose_lint.py at .agents/skills/plain-prose/scripts/prose_lint.py, skills/plain-prose/references/word-list.md at .agents/skills/plain-prose/references/word-list.md. The "GitHub Copilot" tab on this page has the curl commands, or download https://loadout.jnw-it.com/download/no-ai-voice-writing/copilot.zip, which is already laid out. Do not overwrite an existing AGENTS.md or CLAUDE.md; merge it.

Has Writing rules that avoid AI-sounding prose been tested?

It passed the Level 1 automated install checks on 2026-10-17: the files parse, install to each agent's documented paths, and pass the safety scan. No AI agent has run it yet, so no agent pass or fail is claimed.

More for Claude Code, Codex, Cursor, Gemini CLI, Antigravity CLI and GitHub Copilot.